2
* Copyright © 2008 Red Hat, Inc.
3
* Partly based on code Copyright © 2000 SuSE, Inc.
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.
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.
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.
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.
39
* Author: Owen Taylor <otaylor@fishsoup.net>
40
* Based on code by: Keith Packard
45
#include "glamor_priv.h"
50
#define DBG_GLYPH_CACHE(a) ErrorF a
52
#define DBG_GLYPH_CACHE(a)
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
60
/* Maximum number of glyphs we buffer on the stack before flushing
61
* rendering to the mask or destination surface.
63
#define GLYPH_BUFFER_SIZE 1024
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)
75
glamor_composite_rect_t rects[GLYPH_BUFFER_SIZE + 4];
77
} glamor_glyph_buffer_t;
80
glamor_glyph_cache_t *cache;
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. */
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;
95
#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
96
static DevPrivateKeyRec glamor_glyph_key;
98
static inline struct glamor_glyph *
99
glamor_glyph_get_private(GlyphPtr glyph)
101
return (struct glamor_glyph *) glyph->devPrivates;
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.
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.
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
124
struct glamor_glyph_mask_cache_entry {
132
static struct glamor_glyph_mask_cache {
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] = {
141
clear_mask_cache_bitmap(struct glamor_glyph_mask_cache *maskcache,
142
unsigned int clear_mask_bits)
145
BoxRec box[MASK_CACHE_WIDTH];
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;
158
glamor_solid_boxes(maskcache->pixmap, box, box_cnt, 0);
159
maskcache->cleared_bitmap |= clear_mask_bits;
163
clear_mask_cache(struct glamor_glyph_mask_cache *maskcache)
166
int cnt = MASK_CACHE_WIDTH;
168
struct glamor_glyph_mask_cache_entry *mce;
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];
177
mce->y = CACHE_PICTURE_SIZE;
179
x += MASK_CACHE_MAX_SIZE;
182
maskcache->free_bitmap = MASK_CACHE_MASK;
183
maskcache->cleared_bitmap = MASK_CACHE_MASK;
187
find_continuous_bits(unsigned int bits, int bits_cnt, unsigned int *pbits_mask)
190
unsigned int bits_mask;
192
bits_mask = ((1LL << bits_cnt) - 1);
194
if (_X_UNLIKELY(bits_cnt > 56)) {
196
if ((bits & bits_mask) == bits_mask) {
197
*pbits_mask = bits_mask << idx;
207
unsigned int temp_bits;
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);
214
/* Find first zero. And clear the tested bit. */
215
bits &= ~(1LL << idx);
217
bits &= ~((1LL << idx) - 1);
224
static struct glamor_glyph_mask_cache_entry *
225
get_mask_cache(struct glamor_glyph_mask_cache *maskcache, int blocks)
227
int free_cleared_bit, idx = -1;
229
unsigned int bits_mask = 0;
231
if (maskcache->free_bitmap == 0)
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;
239
else if (free_cleared_bit && blocks > 1) {
240
idx = find_continuous_bits(free_cleared_bit, blocks, &bits_mask);
244
clear_mask_cache_bitmap(maskcache, maskcache->free_bitmap);
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];
258
put_mask_cache_bitmap(struct glamor_glyph_mask_cache *maskcache,
261
maskcache->free_bitmap |= bitmap;
262
DEBUGF("put bitmap %x free %x clear %x \n",
263
bitmap, maskcache->free_bitmap, maskcache->cleared_bitmap);
267
glamor_unrealize_glyph_caches(ScreenPtr pScreen)
269
glamor_screen_private *glamor = glamor_get_screen_private(pScreen);
272
if (!glamor->glyph_cache_initialized)
275
for (i = 0; i < GLAMOR_NUM_GLYPH_CACHE_FORMATS; i++) {
276
glamor_glyph_cache_t *cache = &glamor->glyphCaches[i];
279
FreePicture(cache->picture, 0);
287
glamor->glyph_cache_initialized = FALSE;
291
glamor_glyphs_fini(ScreenPtr pScreen)
293
glamor_unrealize_glyph_caches(pScreen);
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
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.
307
glamor_realize_glyph_caches(ScreenPtr pScreen)
309
glamor_screen_private *glamor = glamor_get_screen_private(pScreen);
311
unsigned int formats[] = {
317
memset(glamor->glyphCaches, 0, sizeof(glamor->glyphCaches));
319
for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) {
320
glamor_glyph_cache_t *cache = &glamor->glyphCaches[i];
324
int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
326
PictFormatPtr pPictFormat =
327
PictureMatchFormat(pScreen, depth, formats[i]);
331
/* Now allocate the pixmap and picture */
332
pixmap = pScreen->CreatePixmap(pScreen,
334
CACHE_PICTURE_SIZE + MASK_CACHE_MAX_SIZE,
335
depth, GLAMOR_CREATE_NO_LARGE);
339
component_alpha = NeedsComponent(pPictFormat->format);
340
picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
341
CPComponentAlpha, &component_alpha,
342
serverClient, &error);
344
pScreen->DestroyPixmap(pixmap);
348
ValidatePicture(picture);
350
cache->picture = picture;
351
cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE);
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]);
360
assert(i == GLAMOR_NUM_GLYPH_CACHE_FORMATS);
365
glamor_unrealize_glyph_caches(pScreen);
370
* Called by glamor_create_screen_resources() to set up the glyph cache.
372
* This was previously required to be called by the drivers, but not
373
* as of the xserver 1.16 ABI.
376
glamor_glyphs_init(ScreenPtr pScreen)
378
glamor_screen_private *glamor = glamor_get_screen_private(pScreen);
380
if (glamor->glyph_cache_initialized)
383
if (!dixRegisterPrivateKey(&glamor_glyph_key,
384
PRIVATE_GLYPH, sizeof(struct glamor_glyph)))
387
glamor->glyph_cache_initialized = TRUE;
392
/* The most efficient thing to way to upload the glyph to the screen
393
* is to use CopyArea; glamor pixmaps are always offscreen.
396
glamor_glyph_cache_upload_glyph(ScreenPtr screen,
397
glamor_glyph_cache_t *cache,
398
GlyphPtr glyph, int x, int y)
400
PicturePtr pGlyphPicture = GlyphPicture(glyph)[screen->myNum];
401
PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
402
PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
407
gc = GetScratchGC(pCachePixmap->drawable.depth, screen);
411
ValidateGC(&pCachePixmap->drawable, gc);
413
scratch = pGlyphPixmap;
414
if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) {
416
scratch = glamor_create_pixmap(screen,
419
pCachePixmap->drawable.depth, 0);
429
pCachePixmap->drawable.depth,
430
cache->picture->format),
431
0, NULL, serverClient, &error);
433
ValidatePicture(picture);
434
glamor_composite(PictOpSrc,
438
0, glyph->info.width, glyph->info.height);
439
FreePicture(picture, 0);
443
scratch = pGlyphPixmap;
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);
461
glamor_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph)
463
struct glamor_glyph *priv;
465
/* Use Lookup in case we have not attached to this glyph. */
466
priv = glamor_glyph_get_private(glyph);
469
priv->cache->glyphs[priv->pos] = NULL;
472
/* Cut and paste from render/glyph.c - probably should export it instead */
474
glamor_glyph_extents(int nlist,
475
GlyphListPtr list, GlyphPtr *glyphs, BoxPtr extents)
489
GlyphPtr glyph = *glyphs++;
492
v = x - glyph->info.x;
495
v += glyph->info.width;
499
v = y - glyph->info.y;
502
v += glyph->info.height;
506
x += glyph->info.xOff;
507
y += glyph->info.yOff;
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;
518
glamor_glyph_priv_get_edge_map(GlyphPtr glyph, struct glamor_glyph *priv,
519
PicturePtr glyph_picture)
521
PixmapPtr glyph_pixmap = (PixmapPtr) glyph_picture->pDrawable;
523
unsigned long long left_x1_map = 0, left_x2_map = 0;
524
unsigned long long right_x1_map = 0, right_x2_map = 0;
529
unsigned int left_x1_data = 0, left_x2_data = 0;
530
unsigned int right_x1_data = 0, right_x2_data = 0;
532
bitsPerPixel = glyph_pixmap->drawable.bitsPerPixel;
533
stride = glyph_pixmap->devKind;
534
bits = glyph_pixmap->devPrivate.ptr;
535
width = glyph->info.width;
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;
545
left_x1_map = left_x2_map = 0;
546
right_x1_map = right_x2_map = 0;
548
for (j = 0; j < glyph_pixmap->drawable.height; j++) {
549
if (bitsPerPixel == 8) {
552
data = (unsigned char *) ((unsigned char *) bits + stride * j);
553
left_x1_data = *data++;
554
left_x2_data = *data;
556
(unsigned char *) ((unsigned char *) bits + stride * j + width -
558
right_x1_data = *data++;
559
right_x2_data = *data;
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);
565
*((unsigned int *) bits + stride / 4 * j + width - 2);
567
*((unsigned int *) bits + stride / 4 * j + width - 1);
569
else if (bitsPerPixel == 1) {
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;
577
temp = *((unsigned char *) glyph_pixmap->devPrivate.ptr
578
+ glyph_pixmap->devKind * j
579
+ (glyph_pixmap->drawable.width - 2) / 8);
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);
586
& (1 << ((glyph_pixmap->drawable.width - 1) % 8));
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;
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;
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.
607
#define INTERSECTED_TYPE_MASK 1
608
#define NON_INTERSECTED 0
609
#define INTERSECTED 1
611
struct glamor_glyph_list {
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,
628
int *head_y, int *fixed_cnt, int type, BoxPtr prev_extents)
635
if (type == NON_INTERSECTED) {
636
if (x1 < prev_extents->x2 && x2 > prev_extents->x1
637
&& y1 < prev_extents->y2 && y2 > prev_extents->y1)
639
x_off = (*(cur_glyphs - 1))->info.xOff;
640
y_off = (*(cur_glyphs - 1))->info.yOff;
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);
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;
653
cur_pos = cur_list->len;
654
if (cur_pos <= n_off) {
659
DEBUGF("got %d lists\n", list_cnt);
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;
674
fixed_list->list[0].len = cur_pos - *head_pos - n_off;
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;
689
* This function detects glyph lists's overlapping.
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
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.
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)
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;
723
GlyphPtr *head_glyphs;
724
GlyphListPtr cur_list = list;
725
RegionRec list_region;
726
RegionRec current_region;
730
pixman_region_init(&list_region);
731
need_free_list_region = TRUE;
734
pixman_region_init(¤t_region);
736
extents = pixman_region_extents(¤t_region);
740
x1 = x2 = y1 = y2 = 0;
748
DEBUGF("has %d lists.\n", nlist);
750
BoxRec left_box, right_box = { 0 };
751
Bool has_left_edge_box = FALSE, has_right_edge_box = FALSE;
753
struct glamor_glyph *left_priv = NULL, *right_priv = NULL;
758
left_to_right = TRUE;
761
if (_X_UNLIKELY(!first_list)) {
762
pixman_region_init_with_extents(¤t_region, extents);
763
pixman_region_union(&list_region, &list_region, ¤t_region);
767
head_list = cur_list;
768
head_pos = cur_list->len - n;
771
head_glyphs = glyphs;
774
DEBUGF("current list %p has %d glyphs\n", cur_list, n);
776
GlyphPtr glyph = *glyphs++;
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;
785
&& mask_format != GlyphPicture(glyph)[screen->myNum]->format) {
786
need_free_fixed_list = TRUE;
790
x1 = x - glyph->info.x;
793
y1 = y - glyph->info.y;
796
if (check_fake_overlap)
797
priv = glamor_glyph_get_private(glyph);
799
x2 = x1 + glyph->info.width;
800
y2 = y1 + glyph->info.height;
813
prev_extents = *extents;
816
if (check_fake_overlap && priv
817
&& priv->has_edge_map && glyph->info.yOff == 0) {
819
left_box.x2 = x1 + 1;
822
right_box.x1 = x2 - 2;
823
right_box.x2 = x2 - 1;
825
left_priv = right_priv = priv;
826
has_left_edge_box = TRUE;
827
has_right_edge_box = TRUE;
831
if (_X_UNLIKELY(!first_list)) {
836
if (pixman_region_contains_rectangle
837
(&list_region, ¤t_box) != PIXMAN_REGION_OUT) {
838
need_free_fixed_list = TRUE;
843
if (x1 < extents->x2 && x2 > extents->x1
844
&& y1 < extents->y2 && y2 > extents->y1) {
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;
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;
858
if (left_to_right && has_right_edge_box) {
859
if (x1 == right_box.x1) {
861
((priv->left_x1_map & right_priv->
863
| (priv->left_x2_map & right_priv->
866
goto real_intersected;
868
else if (x1 == right_box.x2) {
870
(priv->left_x1_map & right_priv->
873
#ifdef GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK
874
/* tolerate with two pixels overlap. */
875
intersected &= ~(1 << __fls(intersected));
876
if ((intersected & (intersected - 1)))
878
goto real_intersected;
882
else if (!left_to_right && has_left_edge_box) {
883
if (x2 - 1 == left_box.x1) {
885
(priv->right_x2_map & left_priv->
888
#ifdef GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK
889
/* tolerate with two pixels overlap. */
890
intersected &= ~(1 << __fls(intersected));
891
if ((intersected & (intersected - 1)))
893
goto real_intersected;
896
else if (x2 - 1 == right_box.x2) {
897
if ((priv->right_x1_map & left_priv->
899
|| (priv->right_x2_map & left_priv->
901
goto real_intersected;
905
if (x1 < extents->x2 && x1 + 2 > extents->x1)
906
goto real_intersected;
908
goto non_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;
918
if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
922
cur_list->len - (n + 1),
923
x, y, x1, y1, x2, y2,
924
&head_list, &head_pos,
929
need_free_fixed_list = TRUE;
934
in_non_intersected_list = 0;
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;
946
if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
950
cur_list->len - (n + 1), x, y,
956
INTERSECTED, &prev_extents)) {
957
need_free_fixed_list = TRUE;
961
in_non_intersected_list = 1;
963
prev_extents = *extents;
966
if (check_fake_overlap && priv
967
&& priv->has_edge_map && glyph->info.yOff == 0) {
968
if (!has_left_edge_box || x1 < extents->x1) {
970
left_box.x2 = x1 + 1;
972
has_left_edge_box = TRUE;
976
if (!has_right_edge_box || x2 > extents->x2) {
977
right_box.x1 = x2 - 2;
978
right_box.x2 = x2 - 1;
980
has_right_edge_box = TRUE;
985
if (x1 < extents->x1)
987
if (x2 > extents->x2)
990
if (y1 < extents->y1)
992
if (y2 > extents->y2)
995
x += glyph->info.xOff;
996
y += glyph->info.yOff;
1001
if (in_non_intersected_list == 0 && fixed_cnt == 0) {
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;
1011
if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
1015
cur_list->len - (n + 1), x, y,
1020
&head_y, &fixed_cnt,
1021
(!in_non_intersected_list) | 0x80,
1023
need_free_fixed_list = TRUE;
1029
if (need_free_list_region)
1030
pixman_region_fini(&list_region);
1031
pixman_region_fini(¤t_region);
1033
if (need_free_fixed_list && fixed_cnt >= 0) {
1034
while (fixed_cnt--) {
1035
free(fixed_list[fixed_cnt].list);
1039
DEBUGF("Got %d fixed list \n", fixed_cnt);
1043
static inline unsigned int
1044
glamor_glyph_size_to_count(int size)
1046
size /= GLYPH_MIN_SIZE;
1050
static inline unsigned int
1051
glamor_glyph_count_to_mask(int count)
1053
return ~(count - 1);
1056
static inline unsigned int
1057
glamor_glyph_size_to_mask(int size)
1059
return glamor_glyph_count_to_mask(glamor_glyph_size_to_count(size));
1063
glamor_glyph_cache(glamor_screen_private *glamor, GlyphPtr glyph, int *out_x,
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;
1073
if (glyph->info.width > GLYPH_MAX_SIZE
1074
|| glyph->info.height > GLYPH_MAX_SIZE)
1077
for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
1078
if (glyph->info.width <= size && glyph->info.height <= size)
1081
s = glamor_glyph_size_to_count(size);
1082
mask = glamor_glyph_count_to_mask(s);
1083
pos = (cache->count + s - 1) & mask;
1085
priv = glamor_glyph_get_private(glyph);
1086
if (pos < GLYPH_CACHE_SIZE) {
1087
cache->count = pos + s;
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];
1094
if (evicted == NULL)
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);
1105
evicted_priv = NULL;
1108
if (evicted_priv == NULL) {
1109
int count = glamor_glyph_size_to_count(size);
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];
1116
if (evicted != NULL) {
1118
evicted_priv = glamor_glyph_get_private(evicted);
1120
assert(evicted_priv->pos == pos + s);
1121
evicted_priv->cached = FALSE;
1122
cache->glyphs[pos + s] = NULL;
1127
/* And pick a new eviction position */
1128
cache->evict = rand() % GLYPH_CACHE_SIZE;
1131
cache->glyphs[pos] = glyph;
1133
priv->cache = cache;
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) {
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);
1153
priv->cached = TRUE;
1157
return cache->picture;
1160
typedef void (*glyphs_flush_func) (void *arg);
1161
struct glyphs_flush_dst_arg {
1165
glamor_glyph_buffer_t *buffer;
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;
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
1182
struct glyphs_flush_mask_arg {
1184
glamor_glyph_buffer_t *buffer;
1185
struct glamor_glyph_mask_cache *maskcache;
1186
unsigned int used_bitmap;
1190
glamor_glyphs_flush_mask(struct glyphs_flush_mask_arg *arg)
1192
if (arg->buffer->count > 0) {
1194
glamor_composite_glyph_rects(PictOpAdd, arg->buffer->source,
1196
arg->buffer->count, arg->buffer->rects);
1199
arg->buffer->count = 0;
1200
arg->buffer->source = NULL;
1205
glamor_glyphs_flush_dst(struct glyphs_flush_dst_arg *arg)
1210
if (mask_buffer.count > 0) {
1211
glamor_glyphs_flush_mask(&mask_arg);
1213
if (mask_arg.used_bitmap) {
1214
put_mask_cache_bitmap(mask_arg.maskcache, mask_arg.used_bitmap);
1215
mask_arg.used_bitmap = 0;
1218
if (arg->buffer->count > 0) {
1219
glamor_composite_glyph_rects(arg->op, arg->src,
1220
arg->buffer->source, arg->dst,
1222
&arg->buffer->rects[0]);
1223
arg->buffer->count = 0;
1224
arg->buffer->source = NULL;
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)
1238
ScreenPtr screen = glamor_priv->screen;
1239
glamor_composite_rect_t *rect;
1242
glamor_glyph_cache_t *cache;
1244
if (glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST)
1245
priv = glamor_glyph_get_private(glyph);
1247
if (PICT_FORMAT_BPP(format) == 1)
1250
cache = &glamor_priv->glyphCaches[PICT_FORMAT_RGB(format) != 0];
1252
if (buffer->source && buffer->source != cache->picture && glyphs_flush) {
1253
(*glyphs_flush) (flush_arg);
1254
glyphs_flush = NULL;
1257
if (buffer->count == GLYPH_BUFFER_SIZE && glyphs_flush) {
1258
(*glyphs_flush) (flush_arg);
1259
glyphs_flush = NULL;
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);
1272
assert(glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST);
1274
(*glyphs_flush) (flush_arg);
1275
source = glamor_glyph_cache(glamor_priv, glyph, &x, &y);
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);
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;
1299
rect = &buffer->rects[buffer->count++];
1300
rect->x_src = 0 + dx;
1301
rect->y_src = 0 + dy;
1303
priv = glamor_glyph_get_private(glyph);
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;
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;
1321
return GLAMOR_GLYPH_SUCCESS;
1325
glamor_buffer_glyph_clip(glamor_screen_private *glamor_priv,
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,
1333
glyphs_flush_func flush_func, void *arg)
1337
for (i = 0; i < nrect; i++) {
1342
dst_x = glyph_x - glyph_dx;
1343
dst_y = glyph_y - glyph_dy;
1345
y2 = dst_y + height;
1347
if (rects[i].y1 >= y2)
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)
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)
1358
if (dst_x < x2 && dst_y < y2) {
1360
glamor_buffer_glyph(glamor_priv,
1367
x2 - dst_x, y2 - dst_y,
1368
glyphs_mode, flush_func, arg);
1374
glamor_glyphs_via_mask(CARD8 op,
1377
PictFormatPtr mask_format,
1380
int nlist, GlyphListPtr list, GlyphPtr *glyphs,
1381
Bool use_mask_cache)
1383
PixmapPtr mask_pixmap = 0;
1385
ScreenPtr screen = dst->pDrawable->pScreen;
1386
int width = 0, height = 0;
1388
int x_dst = list->xOff, y_dst = list->yOff;
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;
1405
glamor_glyph_extents(nlist, list, glyphs, &extents);
1407
if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
1409
glamor_priv = glamor_get_screen_private(screen);
1410
width = extents.x2 - extents.x1;
1411
height = extents.y2 - extents.y1;
1413
if (mask_format->depth == 1) {
1414
PictFormatPtr a8Format = PictureMatchFormat(screen, 8, PICT_a8);
1417
mask_format = a8Format;
1420
cache = &glamor_priv->glyphCaches
1421
[PICT_FORMAT_RGB(mask_format->format) != 0];
1422
maskcache = mask_cache[PICT_FORMAT_RGB(mask_format->format) != 0];
1426
if (!use_mask_cache || width > (CACHE_PICTURE_SIZE / 4)
1427
|| height > MASK_CACHE_MAX_SIZE) {
1429
mask_pixmap = glamor_create_pixmap(screen, width, height,
1431
CREATE_PIXMAP_USAGE_SCRATCH);
1433
glamor_destroy_pixmap(mask_pixmap);
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);
1443
need_free_mask = TRUE;
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;
1455
mce = get_mask_cache(maskcache,
1456
(width + MASK_CACHE_MAX_SIZE -
1457
1) / MASK_CACHE_MAX_SIZE);
1460
glamor_glyphs_flush_dst(&dst_arg);
1462
if (retry_cnt > 2) {
1464
goto new_mask_pixmap;
1469
mask = cache->picture;
1472
mce->width = (width + MASK_CACHE_MAX_SIZE - 1) / MASK_CACHE_MAX_SIZE;
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;
1481
pmask_arg->mask = mask;
1482
pmask_arg->buffer = pmask_buffer;
1487
mask_glyphs_cnt += n;
1490
if (glyph->info.width > 0 && glyph->info.height > 0) {
1491
glyphs_flush_func flush_func;
1494
if (need_free_mask) {
1495
if (pmask_buffer->count)
1497
(glyphs_flush_func) glamor_glyphs_flush_mask;
1500
temp_arg = pmask_arg;
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)
1509
(glyphs_flush_func) glamor_glyphs_flush_dst;
1512
temp_arg = &dst_arg;
1514
glamor_buffer_glyph(glamor_priv, pmask_buffer,
1515
mask_format->format,
1518
glyph->info.width, glyph->info.height,
1520
flush_func, (void *) temp_arg);
1522
x += glyph->info.xOff;
1523
y += glyph->info.yOff;
1530
if (need_free_mask) {
1531
glamor_glyphs_flush_mask(pmask_arg);
1532
CompositePicture(op,
1537
y_src + y - y_dst, 0, 0, x, y, width, height);
1538
FreePicture(mask, 0);
1539
glamor_destroy_pixmap(mask_pixmap);
1542
struct glamor_glyph priv;
1543
glyphs_flush_func flush_func;
1551
rects = REGION_RECTS(dst->pCompositeClip);
1552
nrect = REGION_NUM_RECTS(dst->pCompositeClip);
1554
pmask_arg->used_bitmap |= ((1 << mce->width) - 1) << mce->idx;
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;
1564
if (dst_buffer.source == NULL) {
1565
dst_buffer.source = cache->picture;
1567
else if (dst_buffer.source != cache->picture) {
1568
glamor_glyphs_flush_dst(&dst_arg);
1569
dst_buffer.source = cache->picture;
1572
x += dst->pDrawable->x;
1573
y += dst->pDrawable->y;
1575
if (dst_buffer.count || mask_buffer.count)
1576
flush_func = (glyphs_flush_func) glamor_glyphs_flush_dst;
1580
glamor_buffer_glyph_clip(glamor_priv,
1582
mask_format->format,
1587
GLYPHS_DST_MODE_MASK_TO_DST,
1588
flush_func, (void *) &dst_arg);
1593
glamor_glyphs_to_dst(CARD8 op,
1598
int nlist, GlyphListPtr list, GlyphPtr *glyphs)
1600
ScreenPtr screen = dst->pDrawable->pScreen;
1602
int x_dst = list->xOff, y_dst = list->yOff;
1607
glamor_screen_private *glamor_priv;
1609
rects = REGION_RECTS(dst->pCompositeClip);
1610
nrect = REGION_NUM_RECTS(dst->pCompositeClip);
1612
glamor_priv = glamor_get_screen_private(screen);
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;
1623
x = dst->pDrawable->x;
1624
y = dst->pDrawable->y;
1630
dst_glyphs_cnt += n;
1634
if (glyph->info.width > 0 && glyph->info.height > 0) {
1635
glyphs_flush_func flush_func;
1637
if (dst_buffer.count || mask_buffer.count)
1638
flush_func = (glyphs_flush_func) glamor_glyphs_flush_dst;
1641
glamor_buffer_glyph_clip(glamor_priv,
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,
1651
x += glyph->info.xOff;
1652
y += glyph->info.yOff;
1658
#define MAX_FIXED_SIZE
1660
glamor_glyphs_reset_buffer(glamor_glyph_buffer_t *buffer)
1663
buffer->source = NULL;
1667
_glamor_glyphs(CARD8 op,
1670
PictFormatPtr mask_format,
1672
INT16 y_src, int nlist, GlyphListPtr list,
1673
GlyphPtr *glyphs, Bool fallback)
1675
PictFormatShort format;
1676
int fixed_size, fixed_cnt = 0;
1677
struct glamor_glyph_list *fixed_list = NULL;
1678
Bool need_free_list = FALSE;
1680
#ifndef GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK
1681
Bool check_fake_overlap = TRUE;
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;
1692
Bool check_fake_overlap = FALSE;
1695
format = mask_format->depth << 24 | mask_format->format;
1700
glamor_glyphs_reset_buffer(&dst_buffer);
1702
if (!mask_format || (((nlist == 1 && list->len == 1) || op == PictOpAdd)
1704
((mask_format->depth << 24) | mask_format->
1706
glamor_glyphs_to_dst(op, src, dst, x_src, y_src, nlist, list, glyphs);
1710
glamor_glyphs_reset_buffer(&mask_buffer);
1712
/* We have mask_format. Need to check the real overlap or not. */
1713
format = mask_format->depth << 24 | mask_format->format;
1715
fixed_list = calloc(fixed_size, sizeof(*fixed_list));
1716
if (_X_UNLIKELY(fixed_list == NULL))
1718
fixed_cnt = glamor_glyphs_intersect(nlist, list, glyphs,
1719
format, dst->pDrawable->pScreen,
1721
fixed_list, fixed_size);
1724
need_free_list = TRUE;
1726
if (fixed_cnt <= 0) {
1727
if (mask_format == NULL) {
1728
glamor_glyphs_to_dst(op, src, dst, x_src, y_src, nlist,
1733
glamor_glyphs_via_mask(op, src, dst, mask_format,
1734
x_src, y_src, nlist, list, glyphs, FALSE);
1735
goto free_fixed_list;
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.
1749
struct glamor_glyph_list *saved_list;
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,
1758
fixed_list->list, fixed_list->glyphs);
1761
glamor_glyphs_via_mask(op, src, dst,
1762
mask_format, x_src, y_src,
1765
fixed_list->glyphs, TRUE);
1767
free(fixed_list->list);
1771
need_free_list = FALSE;
1775
if (dst_buffer.count || mask_buffer.count)
1776
glamor_glyphs_flush_dst(&dst_arg);
1778
if (need_free_list) {
1779
assert(fixed_cnt <= 0);
1786
glamor_glyphs(CARD8 op,
1789
PictFormatPtr mask_format,
1791
INT16 y_src, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
1793
_glamor_glyphs(op, src, dst, mask_format, x_src,
1794
y_src, nlist, list, glyphs, TRUE);
1798
glamor_glyphs_nf(CARD8 op,
1801
PictFormatPtr mask_format,
1803
INT16 y_src, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
1805
return _glamor_glyphs(op, src, dst, mask_format, x_src,
1806
y_src, nlist, list, glyphs, FALSE);