summit_accel.c revision bf977f5f
1/* 2 * hardware acceleration for Visualize FX 4 3 * 4 * Copyright (C) 2024 Michael Lorenz 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * MICHAEL LORENZ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24/* $NetBSD: summit_accel.c,v 1.7 2025/02/18 12:17:20 macallan Exp $ */ 25 26#include <sys/types.h> 27#include <dev/ic/summitreg.h> 28 29 30#include "ngle.h" 31#include "mipict.h" 32 33//#define DEBUG 34 35void 36 exaPrepareAccess(DrawablePtr pDrawable, int index); 37 38void 39 exaFinishAccess(DrawablePtr pDrawable, int index); 40 41#ifdef DEBUG 42#define ENTER xf86Msg(X_ERROR, "%s\n", __func__) 43#define LEAVE xf86Msg(X_ERROR, "%s done\n", __func__) 44#define DBGMSG xf86Msg 45#else 46#define ENTER 47#define DBGMSG if (0) xf86Msg 48#define LEAVE 49#endif 50 51#define SUMMIT_READ_MODE(m) \ 52 if ((m) != fPtr->read_mode) { \ 53 SummitWait(fPtr); \ 54 NGLEWrite4(fPtr, VISFX_VRAM_READ_MODE, (m)); \ 55 fPtr->read_mode = (m); \ 56 } 57 58#define SUMMIT_WRITE_MODE(m) \ 59 if ((m) != fPtr->write_mode) { \ 60 SummitWait(fPtr); \ 61 NGLEWrite4(fPtr, VISFX_VRAM_WRITE_MODE, (m)); \ 62 fPtr->write_mode = (m); \ 63 } 64 65static inline void 66SummitWait(NGLEPtr fPtr) 67{ 68 int reg, count = 0;; 69 70 ENTER; 71 do { 72 reg = NGLERead4(fPtr, VISFX_STATUS); 73 count++; 74 } while ((reg & 0x01000000) != 0); 75 if (reg != 0) { 76 xf86Msg(X_ERROR, "%s status %08x\n", __func__, reg); 77 xf86Msg(X_ERROR, "fault %08x\n", NGLERead4(fPtr, 0x641040)); 78 } 79 DBGMSG(X_ERROR, "%s: %d\n", __func__, count); 80} 81 82static void 83SummitWaitMarker(ScreenPtr pScreen, int Marker) 84{ 85 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 86 NGLEPtr fPtr = NGLEPTR(pScrn); 87 int reg, count = 0; 88 89 ENTER; 90 do { 91 reg = NGLERead4(fPtr, VISFX_STATUS); 92 count++; 93 } while ((reg & 0x01000000) != 0); 94 if (reg != 0) { 95 xf86Msg(X_ERROR, "%s status %08x\n", __func__, reg); 96 xf86Msg(X_ERROR, "fault %08x\n", NGLERead4(fPtr, 0x641040)); 97 } 98 DBGMSG(X_ERROR, "%s: %d\n", __func__, count); 99} 100 101static void 102SummitWaitFifo(NGLEPtr fPtr, int count) 103{ 104 int reg; 105 do { 106 reg = NGLERead4(fPtr, VISFX_FIFO); 107 } while (reg < count); 108#ifdef DEBUG 109 if (reg != 0x800) xf86Msg(X_ERROR, "%s %x\n", __func__, reg); 110#endif 111} 112 113static Bool 114SummitPrepareCopy 115( 116 PixmapPtr pSrcPixmap, 117 PixmapPtr pDstPixmap, 118 int xdir, 119 int ydir, 120 int alu, 121 Pixel planemask 122) 123{ 124 ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; 125 NGLEPtr fPtr = NGLEPTR(pScrn); 126 int dstoff = exaGetPixmapOffset(pDstPixmap); 127 int srcoff = exaGetPixmapOffset(pSrcPixmap); 128 uint32_t sm, dm; 129 int y; 130 131 ENTER; 132 133 sm = dm = OTC01 | BIN8F | BUFFL; 134 DBGMSG(X_ERROR, "%s %d %d\n", __func__, srcoff, dstoff); 135 136 y = (srcoff >> 13); /* pitch is 8192 bytes in 24 bit */ 137 if (y >= fPtr->fbi.fbi_height) { 138 sm = OTC01 | BIN8F | BUFBL; 139 y -= fPtr->fbi.fbi_height; 140 } 141 fPtr->offset = y; 142 SUMMIT_READ_MODE(sm); 143 144 y = (dstoff >> 13); /* pitch is 8192 bytes in 24 bit */ 145 if (y >= fPtr->fbi.fbi_height) { 146 dm = OTC01 | BIN8F | BUFBL; 147 y -= fPtr->fbi.fbi_height; 148 } 149 fPtr->offsetd = y; 150 SUMMIT_WRITE_MODE(dm); 151 152 SummitWaitFifo(fPtr, 8); 153 if (alu == GXcopy) { 154 NGLEWrite4(fPtr, VISFX_FOE, 0); 155 } else { 156 NGLEWrite4(fPtr, VISFX_FOE, FOE_BLEND_ROP); 157 NGLEWrite4(fPtr, VISFX_IBO, alu); 158 } 159 NGLEWrite4(fPtr, VISFX_PLANE_MASK, planemask); 160 LEAVE; 161 return TRUE; 162} 163 164static void 165SummitCopy 166( 167 PixmapPtr pDstPixmap, 168 int xs, 169 int ys, 170 int xd, 171 int yd, 172 int wi, 173 int he 174) 175{ 176 ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; 177 NGLEPtr fPtr = NGLEPTR(pScrn); 178 179 ENTER; 180 SummitWaitFifo(fPtr, 8); 181 NGLEWrite4(fPtr, VISFX_COPY_SRC, (xs << 16) | (ys + fPtr->offset)); 182 NGLEWrite4(fPtr, VISFX_COPY_WH, (wi << 16) | he); 183 NGLEWrite4(fPtr, VISFX_COPY_DST, (xd << 16) | (yd + fPtr->offsetd)); 184 185 LEAVE; 186} 187 188static void 189SummitDoneCopy(PixmapPtr pDstPixmap) 190{ 191 ENTER; 192 LEAVE; 193} 194 195static Bool 196SummitPrepareSolid( 197 PixmapPtr pPixmap, 198 int alu, 199 Pixel planemask, 200 Pixel fg) 201{ 202 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; 203 NGLEPtr fPtr = NGLEPTR(pScrn); 204 int ofs = exaGetPixmapOffset(pPixmap); 205 int y; 206 uint32_t wm = OTC32 | BIN8F | BUFFL | 0x8c0, rm = OTC01 | BIN8F | BUFFL; 207 208 ENTER; 209 y = (ofs >> 13); /* pitch is 8192 bytes in 24 bit */ 210 if (y >= fPtr->fbi.fbi_height) { 211 wm = OTC32 | BIN8F | BUFBL | 0x8c0; 212 rm = OTC01 | BIN8F | BUFBL; 213 y -= fPtr->fbi.fbi_height; 214 } 215 SUMMIT_READ_MODE(rm); 216 SUMMIT_WRITE_MODE(wm); 217 fPtr->offset = y; 218 SummitWaitFifo(fPtr, 10); 219 if (alu == GXcopy) { 220 NGLEWrite4(fPtr, VISFX_FOE, 0); 221 } else { 222 NGLEWrite4(fPtr, VISFX_FOE, FOE_BLEND_ROP); 223 NGLEWrite4(fPtr, VISFX_IBO, alu); 224 } 225 NGLEWrite4(fPtr, VISFX_FG_COLOUR, fg); 226 NGLEWrite4(fPtr, VISFX_PLANE_MASK, planemask); 227 LEAVE; 228 return TRUE; 229} 230 231static void 232SummitSolid( 233 PixmapPtr pPixmap, 234 int x1, 235 int y1, 236 int x2, 237 int y2) 238{ 239 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; 240 NGLEPtr fPtr = NGLEPTR(pScrn); 241 int wi = x2 - x1, he = y2 - y1; 242 243 ENTER; 244 245 y1 += fPtr->offset; 246 247 SummitWaitFifo(fPtr, 6); 248 NGLEWrite4(fPtr, VISFX_START, (x1 << 16) | y1); 249 NGLEWrite4(fPtr, VISFX_SIZE, (wi << 16) | he); 250 251 LEAVE; 252} 253 254static Bool 255SummitUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, 256 char *src, int src_pitch) 257{ 258 ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; 259 NGLEPtr fPtr = NGLEPTR(pScrn); 260 int ofs = exaGetPixmapOffset(pDst); 261 int i; 262 uint32_t *line, mode = OTC01 | BIN8F | BUFFL; 263 uint8_t *dst; 264 265 ENTER; 266 y += (ofs >> 13); /* pitch is 8192 bytes in 24 bit */ 267 if (y >= fPtr->fbi.fbi_height) { 268 mode = OTC01 | BIN8F | BUFBL; 269 y -= fPtr->fbi.fbi_height; 270 } 271 272 dst = fPtr->fbmem; 273 dst += (y << 13) + (x << 2); 274 275 SUMMIT_WRITE_MODE(mode); 276 NGLEWrite4(fPtr, VISFX_PLANE_MASK, 0xffffffff); 277 NGLEWrite4(fPtr, VISFX_FOE, 0); 278 279 while (h--) { 280 /* 281 * it *should* be impossible to overrun the FIFO using BINC 282 * writes, but overruns are annoying if they do happen so be 283 * overly cautious and make sure there is at least some room 284 */ 285 SummitWaitFifo(fPtr, w + 1); 286 NGLEWrite4(fPtr, VISFX_VRAM_WRITE_DEST, (y << 16) | x); 287 line = (uint32_t *)src; 288 289 for (i = 0; i < w; i++) 290 NGLEWrite4(fPtr, VISFX_VRAM_WRITE_DATA_INCRX, line[i]); 291 //memcpy(dst, src, w << 2); 292 src += src_pitch; 293 dst += 8192; 294 y++; 295 } 296 297 LEAVE; 298 299 return TRUE; 300} 301 302static Bool 303SummitDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, 304 char *dst, int dst_pitch) 305{ 306 ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum]; 307 NGLEPtr fPtr = NGLEPTR(pScrn); 308 uint8_t *src; 309 int ofs = exaGetPixmapOffset(pSrc); 310 uint32_t mode = OTC01 | BIN8F | BUFFL; 311 312 ENTER; 313 314 y += (ofs >> 13); 315 if (y >= fPtr->fbi.fbi_height) { 316 mode = OTC01 | BIN8F | BUFBL; 317 y -= fPtr->fbi.fbi_height; 318 } 319 SUMMIT_READ_MODE(mode); 320 SummitWait(fPtr); 321 NGLEWrite4(fPtr, VISFX_RPH, VISFX_RPH_LTR); 322 SummitWait(fPtr); 323 324 src = fPtr->fbmem; 325 src += (y << 13) + (x << 2); 326 327 while (h--) { 328 memcpy(dst, src, w << 2); 329 src += 8192; 330 dst += dst_pitch; 331 } 332 333 LEAVE; 334 335 return TRUE; 336} 337 338Bool 339SummitPrepareAccess(PixmapPtr pPixmap, int index) 340{ 341 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; 342 NGLEPtr fPtr = NGLEPTR(pScrn); 343 int ofs = exaGetPixmapOffset(pPixmap); 344 int y; 345 346 ENTER; 347 //xf86Msg(X_ERROR, "%s %d\n", __func__, ofs); 348 if (ofs == 0) { 349 /* accessing the visible framebuffer */ 350 SUMMIT_READ_MODE(OTC01 | BIN8F | BUFFL); 351 SUMMIT_WRITE_MODE(OTC01 | BIN8F | BUFFL); 352 } else { 353 SUMMIT_READ_MODE(OTC01 | BIN8F | BUFBL); 354 SUMMIT_WRITE_MODE(OTC01 | BIN8F | BUFBL); 355 y = ofs >> 13; 356 y -= fPtr->fbi.fbi_height; 357 pPixmap->devPrivate.ptr = fPtr->fbmem + (y << 13); 358 } 359 NGLEWrite4(fPtr, VISFX_FOE, 0); 360 NGLEWrite4(fPtr, VISFX_RPH, VISFX_RPH_LTR); 361 //NGLEWrite4(fPtr, VISFX_CONTROL, 0x200); 362 SummitWait(fPtr); 363 LEAVE; 364 return TRUE; 365} 366 367void 368SummitFinishAccess(PixmapPtr pPixmap, int index) 369{ 370 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; 371 NGLEPtr fPtr = NGLEPTR(pScrn); 372 373 ENTER; 374 //NGLEWrite4(fPtr, VISFX_CONTROL, 0); 375 //SummitWait(fPtr); 376 LEAVE; 377} 378 379PixmapPtr 380SummitGetDrawablePixmap(DrawablePtr pDrawable) 381{ 382 if (pDrawable->type == DRAWABLE_WINDOW) 383 return pDrawable->pScreen->GetWindowPixmap((WindowPtr) pDrawable); 384 else 385 return (PixmapPtr) pDrawable; 386} 387 388static void 389SummitDrawGlyph8(NGLEPtr fPtr, int32_t fg, PixmapPtr mask, int p, 390 int xm, int ym, int xd, int yd, int w, int h) 391{ 392 uint8_t *gdata = mask->devPrivate.ptr; 393 uint32_t msk; 394 int i, j; 395 396 gdata += xm; 397 gdata += (p * ym); 398 for (i = 0; i < h; i++) { 399 SummitWaitFifo(fPtr, w * 2); 400 NGLEWrite4(fPtr, VISFX_VRAM_WRITE_DEST, 401 ((yd + i) << 16) | xd); 402 for (j = 0; j < w; j++) { 403 msk = gdata[j]; 404 msk = (msk << 24) | fg; 405 NGLEWrite4(fPtr, 406 VISFX_VRAM_WRITE_DATA_INCRX, msk); 407 } 408 gdata += p; 409 } 410} 411 412static void 413SummitDrawGlyph32(NGLEPtr fPtr, uint32_t fg, PixmapPtr mask, int p, 414 int xm, int ym, int xd, int yd, int w, int h) 415{ 416 uint32_t *gdata = mask->devPrivate.ptr; 417 uint32_t msk; 418 int i, j; 419 420 gdata += xm; 421 gdata += (p * ym); 422 423 for (i = 0; i < h; i++) { 424 SummitWaitFifo(fPtr, w * 2); 425 NGLEWrite4(fPtr, VISFX_VRAM_WRITE_DEST, 426 ((yd + i) << 16) | xd); 427 for (j = 0; j < w; j++) { 428 msk = gdata[j]; 429 msk = (msk & 0xff000000) | fg; 430 NGLEWrite4(fPtr, 431 VISFX_VRAM_WRITE_DATA_INCRX, msk); 432 } 433 gdata += p >> 2; 434 } 435} 436 437static void 438SummitGlyphs (CARD8 op, 439 PicturePtr pSrc, 440 PicturePtr pDst, 441 PictFormatPtr maskFormat, 442 INT16 xSrc, 443 INT16 ySrc, 444 int nlist, 445 GlyphListPtr list, 446 GlyphPtr *glyphs) 447{ 448 ScreenPtr pScreen = pDst->pDrawable->pScreen; 449 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 450 NGLEPtr fPtr = NGLEPTR(pScrn); 451 PicturePtr pPicture; 452 PixmapPtr mask, dst; 453 GlyphPtr glyph; 454 int xDst = list->xOff, yDst = list->yOff; 455 int x = 0, y = 0, i, n, ofs, p, j, wi, he; 456 uint32_t fg = 0xffffffff, msk; 457 458 if (op != PictOpOver) goto fallback; 459 460 if (!exaDrawableIsOffscreen(pDst->pDrawable)) goto fallback; 461 462 dst = SummitGetDrawablePixmap(pDst->pDrawable); 463 ofs = exaGetPixmapOffset(dst); 464 ofs = ofs >> 13; 465 466 if (pDst->pDrawable->type == DRAWABLE_WINDOW) { 467 x += pDst->pDrawable->x; 468 y += pDst->pDrawable->y; 469 } 470 471 if (pSrc->pSourcePict != NULL) { 472 if (pSrc->pSourcePict->type == SourcePictTypeSolidFill) { 473 fg = pSrc->pSourcePict->solidFill.color; 474 } 475 } 476 fg &= 0x00ffffff; 477 478 if (ofs == 0) { 479 /* accessing the visible framebuffer */ 480 SUMMIT_WRITE_MODE(OTC01 | BIN8F | BUFFL); 481 } else { 482 SUMMIT_WRITE_MODE(OTC01 | BIN8F | BUFBL); 483 } 484 485 SummitWaitFifo(fPtr, 4); 486 NGLEWrite4(fPtr, VISFX_FOE, FOE_BLEND_ROP); 487 NGLEWrite4(fPtr, VISFX_IBO, 488 IBO_ADD | SRC(IBO_SRC) | DST(IBO_ONE_MINUS_SRC)); 489 490 while (nlist--) { 491 x += list->xOff; 492 y += list->yOff; 493 n = list->len; 494 while (n--) { 495 glyph = *glyphs++; 496 pPicture = GlyphPicture (glyph)[pScreen->myNum]; 497 if (pPicture) { 498 int xd = x - glyph->info.x; 499 int yd = y - glyph->info.y; 500 RegionRec region; 501 BoxPtr pbox; 502 int nbox; 503 504 if (ofs == 0) { 505 /* 506 * we're drawing to the visible screen, 507 * so we must take care not to scribble 508 * over other windows 509 */ 510 if (!miComputeCompositeRegion(®ion, 511 pSrc, pPicture, pDst, 512 0, 0, 0, 0, xd, yd, 513 glyph->info.width, 514 glyph->info.height)) 515 goto skip; 516 517 fbGetDrawablePixmap(pPicture->pDrawable, 518 mask, wi, he); 519 exaPrepareAccess(pPicture->pDrawable, 520 EXA_PREPARE_SRC); 521 p = exaGetPixmapPitch(mask); 522 523 nbox = RegionNumRects(®ion); 524 pbox = RegionRects(®ion); 525 while (nbox--) { 526 if (pPicture->format == PICT_a8) { 527 SummitDrawGlyph8(fPtr, 528 fg, mask, p, 529 pbox->x1 - xd, 530 pbox->y1 - yd, 531 pbox->x1, pbox->y1, 532 pbox->x2 - pbox->x1, 533 pbox->y2 - pbox->y1); 534 } else { 535 SummitDrawGlyph32(fPtr, 536 fg, mask, p, 537 pbox->x1 - xd, 538 pbox->y1 - yd, 539 pbox->x1, pbox->y1, 540 pbox->x2 - pbox->x1, 541 pbox->y2 - pbox->y1); 542 } 543 pbox++; 544 } 545 RegionUninit(®ion); 546 exaFinishAccess(pPicture->pDrawable, 547 EXA_PREPARE_SRC); 548 } else { 549 /* 550 * drawing into off-screen memory, we 551 * only need to clip to the destination 552 * pixmap's boundaries 553 */ 554 yd += (ofs - fPtr->fbi.fbi_height); 555 556 fbGetDrawablePixmap(pPicture->pDrawable, 557 mask, wi, he); 558 exaPrepareAccess(pPicture->pDrawable, 559 EXA_PREPARE_SRC); 560 p = exaGetPixmapPitch(mask); 561 562 if (pPicture->format == PICT_a8) { 563 SummitDrawGlyph8(fPtr, 564 fg, mask, p, 565 0, 0, 566 xd, yd, 567 glyph->info.width, 568 glyph->info.height); 569 } else { 570 SummitDrawGlyph32(fPtr, 571 fg, mask, p, 572 0, 0, 573 xd, yd, 574 glyph->info.width, 575 glyph->info.height); 576 } 577 exaFinishAccess(pPicture->pDrawable, 578 EXA_PREPARE_SRC); 579 } 580 } 581skip: 582 x += glyph->info.xOff; 583 y += glyph->info.yOff; 584 } 585 list++; 586 } 587 return; 588fallback: 589 fPtr->glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); 590} 591 592Bool 593SummitInitAccel(ScreenPtr pScreen) 594{ 595 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 596 PictureScreenPtr ps = GetPictureScreen(pScreen); 597 NGLEPtr fPtr = NGLEPTR(pScrn); 598 ExaDriverPtr pExa; 599 int bpp = pScrn->bitsPerPixel >> 3, ret; 600 601 pExa = exaDriverAlloc(); 602 if (!pExa) 603 return FALSE; 604 605 fPtr->pExa = pExa; 606 607 pExa->exa_major = EXA_VERSION_MAJOR; 608 pExa->exa_minor = EXA_VERSION_MINOR; 609 610 pExa->memoryBase = fPtr->fbmem; 611 pExa->memorySize = fPtr->fbi.fbi_stride * (fPtr->fbi.fbi_height * 2); 612 pExa->offScreenBase = fPtr->fbi.fbi_stride * fPtr->fbi.fbi_height; 613 pExa->pixmapOffsetAlign = fPtr->fbi.fbi_stride; 614 pExa->pixmapPitchAlign = fPtr->fbi.fbi_stride; 615 616 pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_MIXED_PIXMAPS; 617 618 pExa->maxX = 2048; 619 pExa->maxY = 2048; 620 621 pExa->WaitMarker = SummitWaitMarker; 622 pExa->Solid = SummitSolid; 623 pExa->DoneSolid = SummitDoneCopy; 624 pExa->Copy = SummitCopy; 625 pExa->DoneCopy = SummitDoneCopy; 626 pExa->PrepareCopy = SummitPrepareCopy; 627 pExa->PrepareSolid = SummitPrepareSolid; 628 pExa->UploadToScreen = SummitUploadToScreen; 629 pExa->DownloadFromScreen = SummitDownloadFromScreen; 630 pExa->PrepareAccess = SummitPrepareAccess; 631 pExa->FinishAccess = SummitFinishAccess; 632 633 fPtr->read_mode = -1; 634 fPtr->write_mode = -1; 635 SUMMIT_READ_MODE(OTC01 | BIN8F | BUFFL); 636 SUMMIT_WRITE_MODE(OTC01 | BIN8F | BUFFL); 637 NGLEWrite4(fPtr, VISFX_FOE, FOE_BLEND_ROP); 638 NGLEWrite4(fPtr, VISFX_IBO, GXcopy); 639 NGLEWrite4(fPtr, VISFX_CONTROL, 0); 640 641 ret = exaDriverInit(pScreen, pExa); 642 643 fPtr->glyphs = ps->Glyphs; 644 ps->Glyphs = SummitGlyphs; 645 return ret; 646} 647