1706f2543Smrg/* 2706f2543Smrg * Copyright © 2008 Red Hat, Inc. 3706f2543Smrg * Partly based on code Copyright © 2000 SuSE, Inc. 4706f2543Smrg * 5706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its 6706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that 7706f2543Smrg * the above copyright notice appear in all copies and that both that 8706f2543Smrg * copyright notice and this permission notice appear in supporting 9706f2543Smrg * documentation, and that the name of Red Hat not be used in advertising or 10706f2543Smrg * publicity pertaining to distribution of the software without specific, 11706f2543Smrg * written prior permission. Red Hat makes no representations about the 12706f2543Smrg * suitability of this software for any purpose. It is provided "as is" 13706f2543Smrg * without express or implied warranty. 14706f2543Smrg * 15706f2543Smrg * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16706f2543Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat 17706f2543Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18706f2543Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 19706f2543Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 20706f2543Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21706f2543Smrg * 22706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its 23706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that 24706f2543Smrg * the above copyright notice appear in all copies and that both that 25706f2543Smrg * copyright notice and this permission notice appear in supporting 26706f2543Smrg * documentation, and that the name of SuSE not be used in advertising or 27706f2543Smrg * publicity pertaining to distribution of the software without specific, 28706f2543Smrg * written prior permission. SuSE makes no representations about the 29706f2543Smrg * suitability of this software for any purpose. It is provided "as is" 30706f2543Smrg * without express or implied warranty. 31706f2543Smrg * 32706f2543Smrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 33706f2543Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 34706f2543Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 35706f2543Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 36706f2543Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 37706f2543Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 38706f2543Smrg * 39706f2543Smrg * Author: Owen Taylor <otaylor@fishsoup.net> 40706f2543Smrg * Based on code by: Keith Packard 41706f2543Smrg */ 42706f2543Smrg 43706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 44706f2543Smrg#include <dix-config.h> 45706f2543Smrg#endif 46706f2543Smrg 47706f2543Smrg#include <stdlib.h> 48706f2543Smrg 49706f2543Smrg#include "exa_priv.h" 50706f2543Smrg 51706f2543Smrg#include "mipict.h" 52706f2543Smrg 53706f2543Smrg#if DEBUG_GLYPH_CACHE 54706f2543Smrg#define DBG_GLYPH_CACHE(a) ErrorF a 55706f2543Smrg#else 56706f2543Smrg#define DBG_GLYPH_CACHE(a) 57706f2543Smrg#endif 58706f2543Smrg 59706f2543Smrg/* Width of the pixmaps we use for the caches; this should be less than 60706f2543Smrg * max texture size of the driver; this may need to actually come from 61706f2543Smrg * the driver. 62706f2543Smrg */ 63706f2543Smrg#define CACHE_PICTURE_WIDTH 1024 64706f2543Smrg 65706f2543Smrg/* Maximum number of glyphs we buffer on the stack before flushing 66706f2543Smrg * rendering to the mask or destination surface. 67706f2543Smrg */ 68706f2543Smrg#define GLYPH_BUFFER_SIZE 256 69706f2543Smrg 70706f2543Smrgtypedef struct { 71706f2543Smrg PicturePtr mask; 72706f2543Smrg ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; 73706f2543Smrg int count; 74706f2543Smrg} ExaGlyphBuffer, *ExaGlyphBufferPtr; 75706f2543Smrg 76706f2543Smrgtypedef enum { 77706f2543Smrg ExaGlyphSuccess, /* Glyph added to render buffer */ 78706f2543Smrg ExaGlyphFail, /* out of memory, etc */ 79706f2543Smrg ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */ 80706f2543Smrg} ExaGlyphCacheResult; 81706f2543Smrg 82706f2543Smrgvoid 83706f2543SmrgexaGlyphsInit(ScreenPtr pScreen) 84706f2543Smrg{ 85706f2543Smrg ExaScreenPriv(pScreen); 86706f2543Smrg int i = 0; 87706f2543Smrg 88706f2543Smrg memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches)); 89706f2543Smrg 90706f2543Smrg pExaScr->glyphCaches[i].format = PICT_a8; 91706f2543Smrg pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; 92706f2543Smrg i++; 93706f2543Smrg pExaScr->glyphCaches[i].format = PICT_a8; 94706f2543Smrg pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; 95706f2543Smrg i++; 96706f2543Smrg pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; 97706f2543Smrg pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; 98706f2543Smrg i++; 99706f2543Smrg pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; 100706f2543Smrg pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; 101706f2543Smrg i++; 102706f2543Smrg 103706f2543Smrg assert(i == EXA_NUM_GLYPH_CACHES); 104706f2543Smrg 105706f2543Smrg for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 106706f2543Smrg pExaScr->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth; 107706f2543Smrg pExaScr->glyphCaches[i].size = 256; 108706f2543Smrg pExaScr->glyphCaches[i].hashSize = 557; 109706f2543Smrg } 110706f2543Smrg} 111706f2543Smrg 112706f2543Smrgstatic void 113706f2543SmrgexaUnrealizeGlyphCaches(ScreenPtr pScreen, 114706f2543Smrg unsigned int format) 115706f2543Smrg{ 116706f2543Smrg ExaScreenPriv(pScreen); 117706f2543Smrg int i; 118706f2543Smrg 119706f2543Smrg for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 120706f2543Smrg ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 121706f2543Smrg 122706f2543Smrg if (cache->format != format) 123706f2543Smrg continue; 124706f2543Smrg 125706f2543Smrg if (cache->picture) { 126706f2543Smrg FreePicture ((pointer) cache->picture, (XID) 0); 127706f2543Smrg cache->picture = NULL; 128706f2543Smrg } 129706f2543Smrg 130706f2543Smrg free(cache->hashEntries); 131706f2543Smrg cache->hashEntries = NULL; 132706f2543Smrg 133706f2543Smrg free(cache->glyphs); 134706f2543Smrg cache->glyphs = NULL; 135706f2543Smrg cache->glyphCount = 0; 136706f2543Smrg } 137706f2543Smrg} 138706f2543Smrg 139706f2543Smrg#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) 140706f2543Smrg 141706f2543Smrg/* All caches for a single format share a single pixmap for glyph storage, 142706f2543Smrg * allowing mixing glyphs of different sizes without paying a penalty 143706f2543Smrg * for switching between mask pixmaps. (Note that for a size of font 144706f2543Smrg * right at the border between two sizes, we might be switching for almost 145706f2543Smrg * every glyph.) 146706f2543Smrg * 147706f2543Smrg * This function allocates the storage pixmap, and then fills in the 148706f2543Smrg * rest of the allocated structures for all caches with the given format. 149706f2543Smrg */ 150706f2543Smrgstatic Bool 151706f2543SmrgexaRealizeGlyphCaches(ScreenPtr pScreen, 152706f2543Smrg unsigned int format) 153706f2543Smrg{ 154706f2543Smrg ExaScreenPriv(pScreen); 155706f2543Smrg 156706f2543Smrg int depth = PIXMAN_FORMAT_DEPTH(format); 157706f2543Smrg PictFormatPtr pPictFormat; 158706f2543Smrg PixmapPtr pPixmap; 159706f2543Smrg PicturePtr pPicture; 160706f2543Smrg CARD32 component_alpha; 161706f2543Smrg int height; 162706f2543Smrg int i; 163706f2543Smrg int error; 164706f2543Smrg 165706f2543Smrg pPictFormat = PictureMatchFormat(pScreen, depth, format); 166706f2543Smrg if (!pPictFormat) 167706f2543Smrg return FALSE; 168706f2543Smrg 169706f2543Smrg /* Compute the total vertical size needed for the format */ 170706f2543Smrg 171706f2543Smrg height = 0; 172706f2543Smrg for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 173706f2543Smrg ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 174706f2543Smrg int rows; 175706f2543Smrg 176706f2543Smrg if (cache->format != format) 177706f2543Smrg continue; 178706f2543Smrg 179706f2543Smrg cache->yOffset = height; 180706f2543Smrg 181706f2543Smrg rows = (cache->size + cache->columns - 1) / cache->columns; 182706f2543Smrg height += rows * cache->glyphHeight; 183706f2543Smrg } 184706f2543Smrg 185706f2543Smrg /* Now allocate the pixmap and picture */ 186706f2543Smrg pPixmap = (*pScreen->CreatePixmap) (pScreen, 187706f2543Smrg CACHE_PICTURE_WIDTH, 188706f2543Smrg height, depth, 0); 189706f2543Smrg if (!pPixmap) 190706f2543Smrg return FALSE; 191706f2543Smrg 192706f2543Smrg component_alpha = NeedsComponent(pPictFormat->format); 193706f2543Smrg pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, 194706f2543Smrg CPComponentAlpha, &component_alpha, serverClient, 195706f2543Smrg &error); 196706f2543Smrg 197706f2543Smrg (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ 198706f2543Smrg 199706f2543Smrg if (!pPicture) 200706f2543Smrg return FALSE; 201706f2543Smrg 202706f2543Smrg /* And store the picture in all the caches for the format */ 203706f2543Smrg for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 204706f2543Smrg ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 205706f2543Smrg int j; 206706f2543Smrg 207706f2543Smrg if (cache->format != format) 208706f2543Smrg continue; 209706f2543Smrg 210706f2543Smrg cache->picture = pPicture; 211706f2543Smrg cache->picture->refcnt++; 212706f2543Smrg cache->hashEntries = malloc(sizeof(int) * cache->hashSize); 213706f2543Smrg cache->glyphs = malloc(sizeof(ExaCachedGlyphRec) * cache->size); 214706f2543Smrg cache->glyphCount = 0; 215706f2543Smrg 216706f2543Smrg if (!cache->hashEntries || !cache->glyphs) 217706f2543Smrg goto bail; 218706f2543Smrg 219706f2543Smrg for (j = 0; j < cache->hashSize; j++) 220706f2543Smrg cache->hashEntries[j] = -1; 221706f2543Smrg 222706f2543Smrg cache->evictionPosition = rand() % cache->size; 223706f2543Smrg } 224706f2543Smrg 225706f2543Smrg /* Each cache references the picture individually */ 226706f2543Smrg FreePicture ((pointer) pPicture, (XID) 0); 227706f2543Smrg return TRUE; 228706f2543Smrg 229706f2543Smrgbail: 230706f2543Smrg exaUnrealizeGlyphCaches(pScreen, format); 231706f2543Smrg return FALSE; 232706f2543Smrg} 233706f2543Smrg 234706f2543Smrgvoid 235706f2543SmrgexaGlyphsFini (ScreenPtr pScreen) 236706f2543Smrg{ 237706f2543Smrg ExaScreenPriv(pScreen); 238706f2543Smrg int i; 239706f2543Smrg 240706f2543Smrg for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 241706f2543Smrg ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 242706f2543Smrg 243706f2543Smrg if (cache->picture) 244706f2543Smrg exaUnrealizeGlyphCaches(pScreen, cache->format); 245706f2543Smrg } 246706f2543Smrg} 247706f2543Smrg 248706f2543Smrgstatic int 249706f2543SmrgexaGlyphCacheHashLookup(ExaGlyphCachePtr cache, 250706f2543Smrg GlyphPtr pGlyph) 251706f2543Smrg{ 252706f2543Smrg int slot; 253706f2543Smrg 254706f2543Smrg slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; 255706f2543Smrg 256706f2543Smrg while (TRUE) { /* hash table can never be full */ 257706f2543Smrg int entryPos = cache->hashEntries[slot]; 258706f2543Smrg if (entryPos == -1) 259706f2543Smrg return -1; 260706f2543Smrg 261706f2543Smrg if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){ 262706f2543Smrg return entryPos; 263706f2543Smrg } 264706f2543Smrg 265706f2543Smrg slot--; 266706f2543Smrg if (slot < 0) 267706f2543Smrg slot = cache->hashSize - 1; 268706f2543Smrg } 269706f2543Smrg} 270706f2543Smrg 271706f2543Smrgstatic void 272706f2543SmrgexaGlyphCacheHashInsert(ExaGlyphCachePtr cache, 273706f2543Smrg GlyphPtr pGlyph, 274706f2543Smrg int pos) 275706f2543Smrg{ 276706f2543Smrg int slot; 277706f2543Smrg 278706f2543Smrg memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1)); 279706f2543Smrg 280706f2543Smrg slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; 281706f2543Smrg 282706f2543Smrg while (TRUE) { /* hash table can never be full */ 283706f2543Smrg if (cache->hashEntries[slot] == -1) { 284706f2543Smrg cache->hashEntries[slot] = pos; 285706f2543Smrg return; 286706f2543Smrg } 287706f2543Smrg 288706f2543Smrg slot--; 289706f2543Smrg if (slot < 0) 290706f2543Smrg slot = cache->hashSize - 1; 291706f2543Smrg } 292706f2543Smrg} 293706f2543Smrg 294706f2543Smrgstatic void 295706f2543SmrgexaGlyphCacheHashRemove(ExaGlyphCachePtr cache, 296706f2543Smrg int pos) 297706f2543Smrg{ 298706f2543Smrg int slot; 299706f2543Smrg int emptiedSlot = -1; 300706f2543Smrg 301706f2543Smrg slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize; 302706f2543Smrg 303706f2543Smrg while (TRUE) { /* hash table can never be full */ 304706f2543Smrg int entryPos = cache->hashEntries[slot]; 305706f2543Smrg 306706f2543Smrg if (entryPos == -1) 307706f2543Smrg return; 308706f2543Smrg 309706f2543Smrg if (entryPos == pos) { 310706f2543Smrg cache->hashEntries[slot] = -1; 311706f2543Smrg emptiedSlot = slot; 312706f2543Smrg } else if (emptiedSlot != -1) { 313706f2543Smrg /* See if we can move this entry into the emptied slot, we can't 314706f2543Smrg * do that if if entry would have hashed between the current position 315706f2543Smrg * and the emptied slot. (taking wrapping into account). Bad positions 316706f2543Smrg * are: 317706f2543Smrg * 318706f2543Smrg * | XXXXXXXXXX | 319706f2543Smrg * i j 320706f2543Smrg * 321706f2543Smrg * |XXX XXXX| 322706f2543Smrg * j i 323706f2543Smrg * 324706f2543Smrg * i - slot, j - emptiedSlot 325706f2543Smrg * 326706f2543Smrg * (Knuth 6.4R) 327706f2543Smrg */ 328706f2543Smrg 329706f2543Smrg int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize; 330706f2543Smrg 331706f2543Smrg if (!((entrySlot >= slot && entrySlot < emptiedSlot) || 332706f2543Smrg (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot)))) 333706f2543Smrg { 334706f2543Smrg cache->hashEntries[emptiedSlot] = entryPos; 335706f2543Smrg cache->hashEntries[slot] = -1; 336706f2543Smrg emptiedSlot = slot; 337706f2543Smrg } 338706f2543Smrg } 339706f2543Smrg 340706f2543Smrg slot--; 341706f2543Smrg if (slot < 0) 342706f2543Smrg slot = cache->hashSize - 1; 343706f2543Smrg } 344706f2543Smrg} 345706f2543Smrg 346706f2543Smrg#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) 347706f2543Smrg#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) 348706f2543Smrg 349706f2543Smrg/* The most efficient thing to way to upload the glyph to the screen 350706f2543Smrg * is to use the UploadToScreen() driver hook; this allows us to 351706f2543Smrg * pipeline glyph uploads and to avoid creating gpu backed pixmaps for 352706f2543Smrg * glyphs that we'll never use again. 353706f2543Smrg * 354706f2543Smrg * If we can't do it with UploadToScreen (because the glyph has a gpu copy, 355706f2543Smrg * etc), we fall back to CompositePicture. 356706f2543Smrg * 357706f2543Smrg * We need to damage the cache pixmap manually in either case because the damage 358706f2543Smrg * layer unwrapped the picture screen before calling exaGlyphs. 359706f2543Smrg */ 360706f2543Smrgstatic void 361706f2543SmrgexaGlyphCacheUploadGlyph(ScreenPtr pScreen, 362706f2543Smrg ExaGlyphCachePtr cache, 363706f2543Smrg int x, 364706f2543Smrg int y, 365706f2543Smrg GlyphPtr pGlyph) 366706f2543Smrg{ 367706f2543Smrg ExaScreenPriv(pScreen); 368706f2543Smrg PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; 369706f2543Smrg PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable; 370706f2543Smrg ExaPixmapPriv(pGlyphPixmap); 371706f2543Smrg PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable; 372706f2543Smrg 373706f2543Smrg if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked) 374706f2543Smrg goto composite; 375706f2543Smrg 376706f2543Smrg /* If the glyph pixmap is already uploaded, no point in doing 377706f2543Smrg * things this way */ 378706f2543Smrg if (exaPixmapHasGpuCopy(pGlyphPixmap)) 379706f2543Smrg goto composite; 380706f2543Smrg 381706f2543Smrg /* UploadToScreen only works if bpp match */ 382706f2543Smrg if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel) 383706f2543Smrg goto composite; 384706f2543Smrg 385706f2543Smrg if (pExaScr->do_migration) { 386706f2543Smrg ExaMigrationRec pixmaps[1]; 387706f2543Smrg 388706f2543Smrg /* cache pixmap must have a gpu copy. */ 389706f2543Smrg pixmaps[0].as_dst = TRUE; 390706f2543Smrg pixmaps[0].as_src = FALSE; 391706f2543Smrg pixmaps[0].pPix = pCachePixmap; 392706f2543Smrg pixmaps[0].pReg = NULL; 393706f2543Smrg exaDoMigration (pixmaps, 1, TRUE); 394706f2543Smrg } 395706f2543Smrg 396706f2543Smrg if (!exaPixmapHasGpuCopy(pCachePixmap)) 397706f2543Smrg goto composite; 398706f2543Smrg 399706f2543Smrg /* x,y are in pixmap coordinates, no need for cache{X,Y}off */ 400706f2543Smrg if (pExaScr->info->UploadToScreen(pCachePixmap, 401706f2543Smrg x, 402706f2543Smrg y, 403706f2543Smrg pGlyph->info.width, 404706f2543Smrg pGlyph->info.height, 405706f2543Smrg (char *)pExaPixmap->sys_ptr, 406706f2543Smrg pExaPixmap->sys_pitch)) 407706f2543Smrg goto damage; 408706f2543Smrg 409706f2543Smrgcomposite: 410706f2543Smrg CompositePicture (PictOpSrc, 411706f2543Smrg pGlyphPicture, 412706f2543Smrg None, 413706f2543Smrg cache->picture, 414706f2543Smrg 0, 0, 415706f2543Smrg 0, 0, 416706f2543Smrg x, 417706f2543Smrg y, 418706f2543Smrg pGlyph->info.width, 419706f2543Smrg pGlyph->info.height); 420706f2543Smrg 421706f2543Smrgdamage: 422706f2543Smrg /* The cache pixmap isn't a window, so no need to offset coordinates. */ 423706f2543Smrg exaPixmapDirty (pCachePixmap, 424706f2543Smrg x, 425706f2543Smrg y, 426706f2543Smrg x + cache->glyphWidth, 427706f2543Smrg y + cache->glyphHeight); 428706f2543Smrg} 429706f2543Smrg 430706f2543Smrgstatic ExaGlyphCacheResult 431706f2543SmrgexaGlyphCacheBufferGlyph(ScreenPtr pScreen, 432706f2543Smrg ExaGlyphCachePtr cache, 433706f2543Smrg ExaGlyphBufferPtr buffer, 434706f2543Smrg GlyphPtr pGlyph, 435706f2543Smrg PicturePtr pSrc, 436706f2543Smrg PicturePtr pDst, 437706f2543Smrg INT16 xSrc, 438706f2543Smrg INT16 ySrc, 439706f2543Smrg INT16 xMask, 440706f2543Smrg INT16 yMask, 441706f2543Smrg INT16 xDst, 442706f2543Smrg INT16 yDst) 443706f2543Smrg{ 444706f2543Smrg ExaCompositeRectPtr rect; 445706f2543Smrg int pos; 446706f2543Smrg int x, y; 447706f2543Smrg 448706f2543Smrg if (buffer->mask && buffer->mask != cache->picture) 449706f2543Smrg return ExaGlyphNeedFlush; 450706f2543Smrg 451706f2543Smrg if (!cache->picture) { 452706f2543Smrg if (!exaRealizeGlyphCaches(pScreen, cache->format)) 453706f2543Smrg return ExaGlyphFail; 454706f2543Smrg } 455706f2543Smrg 456706f2543Smrg DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", 457706f2543Smrg cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB", 458706f2543Smrg (long)*(CARD32 *) pGlyph->sha1)); 459706f2543Smrg 460706f2543Smrg pos = exaGlyphCacheHashLookup(cache, pGlyph); 461706f2543Smrg if (pos != -1) { 462706f2543Smrg DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); 463706f2543Smrg x = CACHE_X(pos); 464706f2543Smrg y = CACHE_Y(pos); 465706f2543Smrg } else { 466706f2543Smrg if (cache->glyphCount < cache->size) { 467706f2543Smrg /* Space remaining; we fill from the start */ 468706f2543Smrg pos = cache->glyphCount; 469706f2543Smrg x = CACHE_X(pos); 470706f2543Smrg y = CACHE_Y(pos); 471706f2543Smrg cache->glyphCount++; 472706f2543Smrg DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); 473706f2543Smrg 474706f2543Smrg exaGlyphCacheHashInsert(cache, pGlyph, pos); 475706f2543Smrg 476706f2543Smrg } else { 477706f2543Smrg /* Need to evict an entry. We have to see if any glyphs 478706f2543Smrg * already in the output buffer were at this position in 479706f2543Smrg * the cache 480706f2543Smrg */ 481706f2543Smrg pos = cache->evictionPosition; 482706f2543Smrg x = CACHE_X(pos); 483706f2543Smrg y = CACHE_Y(pos); 484706f2543Smrg DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); 485706f2543Smrg if (buffer->count) { 486706f2543Smrg int i; 487706f2543Smrg 488706f2543Smrg for (i = 0; i < buffer->count; i++) { 489706f2543Smrg if (pSrc ? 490706f2543Smrg (buffer->rects[i].xMask == x && buffer->rects[i].yMask == y) : 491706f2543Smrg (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y)) { 492706f2543Smrg DBG_GLYPH_CACHE((" must flush buffer\n")); 493706f2543Smrg return ExaGlyphNeedFlush; 494706f2543Smrg } 495706f2543Smrg } 496706f2543Smrg } 497706f2543Smrg 498706f2543Smrg /* OK, we're all set, swap in the new glyph */ 499706f2543Smrg exaGlyphCacheHashRemove(cache, pos); 500706f2543Smrg exaGlyphCacheHashInsert(cache, pGlyph, pos); 501706f2543Smrg 502706f2543Smrg /* And pick a new eviction position */ 503706f2543Smrg cache->evictionPosition = rand() % cache->size; 504706f2543Smrg } 505706f2543Smrg 506706f2543Smrg exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph); 507706f2543Smrg } 508706f2543Smrg 509706f2543Smrg buffer->mask = cache->picture; 510706f2543Smrg 511706f2543Smrg rect = &buffer->rects[buffer->count]; 512706f2543Smrg 513706f2543Smrg if (pSrc) 514706f2543Smrg { 515706f2543Smrg rect->xSrc = xSrc; 516706f2543Smrg rect->ySrc = ySrc; 517706f2543Smrg rect->xMask = x; 518706f2543Smrg rect->yMask = y; 519706f2543Smrg } 520706f2543Smrg else 521706f2543Smrg { 522706f2543Smrg rect->xSrc = x; 523706f2543Smrg rect->ySrc = y; 524706f2543Smrg rect->xMask = 0; 525706f2543Smrg rect->yMask = 0; 526706f2543Smrg } 527706f2543Smrg 528706f2543Smrg rect->pDst = pDst; 529706f2543Smrg rect->xDst = xDst; 530706f2543Smrg rect->yDst = yDst; 531706f2543Smrg rect->width = pGlyph->info.width; 532706f2543Smrg rect->height = pGlyph->info.height; 533706f2543Smrg 534706f2543Smrg buffer->count++; 535706f2543Smrg 536706f2543Smrg return ExaGlyphSuccess; 537706f2543Smrg} 538706f2543Smrg 539706f2543Smrg#undef CACHE_X 540706f2543Smrg#undef CACHE_Y 541706f2543Smrg 542706f2543Smrgstatic ExaGlyphCacheResult 543706f2543SmrgexaBufferGlyph(ScreenPtr pScreen, 544706f2543Smrg ExaGlyphBufferPtr buffer, 545706f2543Smrg GlyphPtr pGlyph, 546706f2543Smrg PicturePtr pSrc, 547706f2543Smrg PicturePtr pDst, 548706f2543Smrg INT16 xSrc, 549706f2543Smrg INT16 ySrc, 550706f2543Smrg INT16 xMask, 551706f2543Smrg INT16 yMask, 552706f2543Smrg INT16 xDst, 553706f2543Smrg INT16 yDst) 554706f2543Smrg{ 555706f2543Smrg ExaScreenPriv(pScreen); 556706f2543Smrg unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; 557706f2543Smrg int width = pGlyph->info.width; 558706f2543Smrg int height = pGlyph->info.height; 559706f2543Smrg ExaCompositeRectPtr rect; 560706f2543Smrg PicturePtr mask; 561706f2543Smrg int i; 562706f2543Smrg 563706f2543Smrg if (buffer->count == GLYPH_BUFFER_SIZE) 564706f2543Smrg return ExaGlyphNeedFlush; 565706f2543Smrg 566706f2543Smrg if (PICT_FORMAT_BPP(format) == 1) 567706f2543Smrg format = PICT_a8; 568706f2543Smrg 569706f2543Smrg for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 570706f2543Smrg ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 571706f2543Smrg 572706f2543Smrg if (format == cache->format && 573706f2543Smrg width <= cache->glyphWidth && 574706f2543Smrg height <= cache->glyphHeight) { 575706f2543Smrg ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, 576706f2543Smrg &pExaScr->glyphCaches[i], 577706f2543Smrg buffer, 578706f2543Smrg pGlyph, 579706f2543Smrg pSrc, 580706f2543Smrg pDst, 581706f2543Smrg xSrc, ySrc, 582706f2543Smrg xMask, yMask, 583706f2543Smrg xDst, yDst); 584706f2543Smrg switch (result) { 585706f2543Smrg case ExaGlyphFail: 586706f2543Smrg break; 587706f2543Smrg case ExaGlyphSuccess: 588706f2543Smrg case ExaGlyphNeedFlush: 589706f2543Smrg return result; 590706f2543Smrg } 591706f2543Smrg } 592706f2543Smrg } 593706f2543Smrg 594706f2543Smrg /* Couldn't find the glyph in the cache, use the glyph picture directly */ 595706f2543Smrg 596706f2543Smrg mask = GlyphPicture(pGlyph)[pScreen->myNum]; 597706f2543Smrg if (buffer->mask && buffer->mask != mask) 598706f2543Smrg return ExaGlyphNeedFlush; 599706f2543Smrg 600706f2543Smrg buffer->mask = mask; 601706f2543Smrg 602706f2543Smrg rect = &buffer->rects[buffer->count]; 603706f2543Smrg rect->xSrc = xSrc; 604706f2543Smrg rect->ySrc = ySrc; 605706f2543Smrg rect->xMask = xMask; 606706f2543Smrg rect->yMask = yMask; 607706f2543Smrg rect->xDst = xDst; 608706f2543Smrg rect->yDst = yDst; 609706f2543Smrg rect->width = width; 610706f2543Smrg rect->height = height; 611706f2543Smrg 612706f2543Smrg buffer->count++; 613706f2543Smrg 614706f2543Smrg return ExaGlyphSuccess; 615706f2543Smrg} 616706f2543Smrg 617706f2543Smrgstatic void 618706f2543SmrgexaGlyphsToMask(PicturePtr pMask, 619706f2543Smrg ExaGlyphBufferPtr buffer) 620706f2543Smrg{ 621706f2543Smrg exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask, 622706f2543Smrg buffer->count, buffer->rects); 623706f2543Smrg 624706f2543Smrg buffer->count = 0; 625706f2543Smrg buffer->mask = NULL; 626706f2543Smrg} 627706f2543Smrg 628706f2543Smrgstatic void 629706f2543SmrgexaGlyphsToDst(PicturePtr pSrc, 630706f2543Smrg PicturePtr pDst, 631706f2543Smrg ExaGlyphBufferPtr buffer) 632706f2543Smrg{ 633706f2543Smrg exaCompositeRects(PictOpOver, pSrc, buffer->mask, pDst, buffer->count, 634706f2543Smrg buffer->rects); 635706f2543Smrg 636706f2543Smrg buffer->count = 0; 637706f2543Smrg buffer->mask = NULL; 638706f2543Smrg} 639706f2543Smrg 640706f2543Smrg/* Cut and paste from render/glyph.c - probably should export it instead */ 641706f2543Smrgstatic void 642706f2543SmrgGlyphExtents (int nlist, 643706f2543Smrg GlyphListPtr list, 644706f2543Smrg GlyphPtr *glyphs, 645706f2543Smrg BoxPtr extents) 646706f2543Smrg{ 647706f2543Smrg int x1, x2, y1, y2; 648706f2543Smrg int n; 649706f2543Smrg GlyphPtr glyph; 650706f2543Smrg int x, y; 651706f2543Smrg 652706f2543Smrg x = 0; 653706f2543Smrg y = 0; 654706f2543Smrg extents->x1 = MAXSHORT; 655706f2543Smrg extents->x2 = MINSHORT; 656706f2543Smrg extents->y1 = MAXSHORT; 657706f2543Smrg extents->y2 = MINSHORT; 658706f2543Smrg while (nlist--) 659706f2543Smrg { 660706f2543Smrg x += list->xOff; 661706f2543Smrg y += list->yOff; 662706f2543Smrg n = list->len; 663706f2543Smrg list++; 664706f2543Smrg while (n--) 665706f2543Smrg { 666706f2543Smrg glyph = *glyphs++; 667706f2543Smrg x1 = x - glyph->info.x; 668706f2543Smrg if (x1 < MINSHORT) 669706f2543Smrg x1 = MINSHORT; 670706f2543Smrg y1 = y - glyph->info.y; 671706f2543Smrg if (y1 < MINSHORT) 672706f2543Smrg y1 = MINSHORT; 673706f2543Smrg x2 = x1 + glyph->info.width; 674706f2543Smrg if (x2 > MAXSHORT) 675706f2543Smrg x2 = MAXSHORT; 676706f2543Smrg y2 = y1 + glyph->info.height; 677706f2543Smrg if (y2 > MAXSHORT) 678706f2543Smrg y2 = MAXSHORT; 679706f2543Smrg if (x1 < extents->x1) 680706f2543Smrg extents->x1 = x1; 681706f2543Smrg if (x2 > extents->x2) 682706f2543Smrg extents->x2 = x2; 683706f2543Smrg if (y1 < extents->y1) 684706f2543Smrg extents->y1 = y1; 685706f2543Smrg if (y2 > extents->y2) 686706f2543Smrg extents->y2 = y2; 687706f2543Smrg x += glyph->info.xOff; 688706f2543Smrg y += glyph->info.yOff; 689706f2543Smrg } 690706f2543Smrg } 691706f2543Smrg} 692706f2543Smrg 693706f2543Smrgvoid 694706f2543SmrgexaGlyphs (CARD8 op, 695706f2543Smrg PicturePtr pSrc, 696706f2543Smrg PicturePtr pDst, 697706f2543Smrg PictFormatPtr maskFormat, 698706f2543Smrg INT16 xSrc, 699706f2543Smrg INT16 ySrc, 700706f2543Smrg int nlist, 701706f2543Smrg GlyphListPtr list, 702706f2543Smrg GlyphPtr *glyphs) 703706f2543Smrg{ 704706f2543Smrg PixmapPtr pMaskPixmap = 0; 705706f2543Smrg PicturePtr pMask = NULL; 706706f2543Smrg ScreenPtr pScreen = pDst->pDrawable->pScreen; 707706f2543Smrg int width = 0, height = 0; 708706f2543Smrg int x, y; 709706f2543Smrg int first_xOff = list->xOff, first_yOff = list->yOff; 710706f2543Smrg int n; 711706f2543Smrg GlyphPtr glyph; 712706f2543Smrg int error; 713706f2543Smrg BoxRec extents = {0, 0, 0, 0}; 714706f2543Smrg CARD32 component_alpha; 715706f2543Smrg ExaGlyphBuffer buffer; 716706f2543Smrg 717706f2543Smrg if (maskFormat) 718706f2543Smrg { 719706f2543Smrg ExaScreenPriv(pScreen); 720706f2543Smrg GCPtr pGC; 721706f2543Smrg xRectangle rect; 722706f2543Smrg 723706f2543Smrg GlyphExtents (nlist, list, glyphs, &extents); 724706f2543Smrg 725706f2543Smrg if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) 726706f2543Smrg return; 727706f2543Smrg width = extents.x2 - extents.x1; 728706f2543Smrg height = extents.y2 - extents.y1; 729706f2543Smrg 730706f2543Smrg if (maskFormat->depth == 1) { 731706f2543Smrg PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8); 732706f2543Smrg 733706f2543Smrg if (a8Format) 734706f2543Smrg maskFormat = a8Format; 735706f2543Smrg } 736706f2543Smrg 737706f2543Smrg pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 738706f2543Smrg maskFormat->depth, 739706f2543Smrg CREATE_PIXMAP_USAGE_SCRATCH); 740706f2543Smrg if (!pMaskPixmap) 741706f2543Smrg return; 742706f2543Smrg component_alpha = NeedsComponent(maskFormat->format); 743706f2543Smrg pMask = CreatePicture (0, &pMaskPixmap->drawable, 744706f2543Smrg maskFormat, CPComponentAlpha, &component_alpha, 745706f2543Smrg serverClient, &error); 746706f2543Smrg if (!pMask || 747706f2543Smrg (!component_alpha && pExaScr->info->CheckComposite && 748706f2543Smrg !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask))) 749706f2543Smrg { 750706f2543Smrg PictFormatPtr argbFormat; 751706f2543Smrg 752706f2543Smrg (*pScreen->DestroyPixmap) (pMaskPixmap); 753706f2543Smrg 754706f2543Smrg if (!pMask) 755706f2543Smrg return; 756706f2543Smrg 757706f2543Smrg /* The driver can't seem to composite to a8, let's try argb (but 758706f2543Smrg * without component-alpha) */ 759706f2543Smrg FreePicture ((pointer) pMask, (XID) 0); 760706f2543Smrg 761706f2543Smrg argbFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); 762706f2543Smrg 763706f2543Smrg if (argbFormat) 764706f2543Smrg maskFormat = argbFormat; 765706f2543Smrg 766706f2543Smrg pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 767706f2543Smrg maskFormat->depth, 768706f2543Smrg CREATE_PIXMAP_USAGE_SCRATCH); 769706f2543Smrg if (!pMaskPixmap) 770706f2543Smrg return; 771706f2543Smrg 772706f2543Smrg pMask = CreatePicture (0, &pMaskPixmap->drawable, maskFormat, 0, 0, 773706f2543Smrg serverClient, &error); 774706f2543Smrg if (!pMask) { 775706f2543Smrg (*pScreen->DestroyPixmap) (pMaskPixmap); 776706f2543Smrg return; 777706f2543Smrg } 778706f2543Smrg } 779706f2543Smrg pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); 780706f2543Smrg ValidateGC (&pMaskPixmap->drawable, pGC); 781706f2543Smrg rect.x = 0; 782706f2543Smrg rect.y = 0; 783706f2543Smrg rect.width = width; 784706f2543Smrg rect.height = height; 785706f2543Smrg (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); 786706f2543Smrg FreeScratchGC (pGC); 787706f2543Smrg x = -extents.x1; 788706f2543Smrg y = -extents.y1; 789706f2543Smrg } 790706f2543Smrg else 791706f2543Smrg { 792706f2543Smrg x = 0; 793706f2543Smrg y = 0; 794706f2543Smrg } 795706f2543Smrg buffer.count = 0; 796706f2543Smrg buffer.mask = NULL; 797706f2543Smrg while (nlist--) 798706f2543Smrg { 799706f2543Smrg x += list->xOff; 800706f2543Smrg y += list->yOff; 801706f2543Smrg n = list->len; 802706f2543Smrg while (n--) 803706f2543Smrg { 804706f2543Smrg glyph = *glyphs++; 805706f2543Smrg 806706f2543Smrg if (glyph->info.width > 0 && glyph->info.height > 0) 807706f2543Smrg { 808706f2543Smrg /* pGlyph->info.{x,y} compensate for empty space in the glyph. */ 809706f2543Smrg if (maskFormat) 810706f2543Smrg { 811706f2543Smrg if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, 812706f2543Smrg 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y) == ExaGlyphNeedFlush) 813706f2543Smrg { 814706f2543Smrg exaGlyphsToMask(pMask, &buffer); 815706f2543Smrg exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, 816706f2543Smrg 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y); 817706f2543Smrg } 818706f2543Smrg } 819706f2543Smrg else 820706f2543Smrg { 821706f2543Smrg if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, 822706f2543Smrg xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, 823706f2543Smrg 0, 0, x - glyph->info.x, y - glyph->info.y) 824706f2543Smrg == ExaGlyphNeedFlush) 825706f2543Smrg { 826706f2543Smrg exaGlyphsToDst(pSrc, pDst, &buffer); 827706f2543Smrg exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, 828706f2543Smrg xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, 829706f2543Smrg 0, 0, x - glyph->info.x, y - glyph->info.y); 830706f2543Smrg } 831706f2543Smrg } 832706f2543Smrg } 833706f2543Smrg 834706f2543Smrg x += glyph->info.xOff; 835706f2543Smrg y += glyph->info.yOff; 836706f2543Smrg } 837706f2543Smrg list++; 838706f2543Smrg } 839706f2543Smrg 840706f2543Smrg if (buffer.count) { 841706f2543Smrg if (maskFormat) 842706f2543Smrg exaGlyphsToMask(pMask, &buffer); 843706f2543Smrg else 844706f2543Smrg exaGlyphsToDst(pSrc, pDst, &buffer); 845706f2543Smrg } 846706f2543Smrg 847706f2543Smrg if (maskFormat) 848706f2543Smrg { 849706f2543Smrg x = extents.x1; 850706f2543Smrg y = extents.y1; 851706f2543Smrg CompositePicture (op, 852706f2543Smrg pSrc, 853706f2543Smrg pMask, 854706f2543Smrg pDst, 855706f2543Smrg xSrc + x - first_xOff, 856706f2543Smrg ySrc + y - first_yOff, 857706f2543Smrg 0, 0, 858706f2543Smrg x, y, 859706f2543Smrg width, height); 860706f2543Smrg FreePicture ((pointer) pMask, (XID) 0); 861706f2543Smrg (*pScreen->DestroyPixmap) (pMaskPixmap); 862706f2543Smrg } 863706f2543Smrg} 864