/* * Copyright 2007 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software") * to deal in the software without restriction, including without limitation * on the rights to use, copy, modify, merge, publish, distribute, sub * license, and/or sell copies of the Software, and to permit persons to whom * them Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Adam Jackson */ /* * This implements GC, Render, and Xv polydispatch for GPUs with disjoint * CRTC allocations, as well as provides a mechanism for enabling and * disabling this polydispatch at runtime. * * The problem is that if all CRTCs for a GPU are required to scan out of * the same buffer, the driver may need to constrain the size of this * allocation in order to be able to do accelerated rendering. For example, * you may be able to scan out up to a width of 2k pixels on each of two * CRTCs, but your blitter is also limited to a pitch of 2k; so you can't * have a solid allocation that's 4k pixels wide, because your blitter * won't be able to work with it. Instead you want separate allocations * for each CRTC, and to iterate rendering across each one. * * This code cribs heavily from the DMX multiplexing code. We depend on * the Composite extension, in that the CRTC pixmaps are given non-zero * screen_[xy] even though they're not redirected windows. The rendering * layers under us need to be able to cope with that, but if all else fails * that's what miext/cw is for. * * Possible future work: * * - rrmx_translate_gc() takes an argument for which bits of GC state to * modify, but ignores it. We don't need to translate everything for * every GC op, although this does constrain the underlying renderer's * freedom a bit. * * - Because CRTC pixmaps have screen coordinates, we don't need to * translate primitive geometry before handing it to the lower layers. * However we do have to copy it aside before every dispatch because * we can't depend on the lower layers not to modify it. That would be * a nice invariant to have. It might also be interesting to actively * subset primitive lists before sending them lower in the stack, but * at least for the core X primitives this is unlikely to ever make real * world usage better. */ #ifdef HAVE_DIX_CONFIG_H #include #endif typedef struct _mx_screen_private { CreateGCProcPtr CreateGC; RRCrtcPtr current_crtc; DrawablePtr shattered_root; } mx_screen_private; typedef struct _mx_gc_private { GCOps * wrap; GCFuncs * funcs; } mx_gc_private; static int rrmxGeneration = -1; static int rrmxScreenPrivateIndex = -1; static int rrmxGCPrivateIndex = -1; /*** Internal utilities ***/ static mx_gc_private * rrmx_get_gc_private(ScreenPtr pScreen) { return pGC->devPrivates[rrmxGCPrivateIndex].ptr; } static mx_screen_private * rrmx_get_screen_private(ScreenPtr pScreen) { return pScreen->devPrivates[rrmxScreenPrivateIndex].ptr; } static void rrmx_box(BoxPtr box, int x, int y, int w, int h) { box->x1 = x; box->y1 = y; box->x2 = x + w; box->y2 = y + h; } static RegionPtr rrmx_box_region(int x, int y, int w, int h) { BoxRec box; rrmx_box(&box, x, y, w, h); return miRegionCreate(&box, 1); } /* * Translate a GC relative to a CRTC. Copy most state from the src GC * into the dst GC, translate clipping and tile/stipple origin, and * validate the result against the CRTC's pixmap. * * Returns a boolean indicating if the resulting translation describes * a non-empty region. Therefore we don't even dispatch to CRTCs we're * not going to draw to. * * TODO: Extend this to take an argument for which GC components to * modify. No point in translating tile/stipple for PutImage. */ static Bool rrmx_translate_gc(GCPtr dst, GCPtr src, RRCrtcPtr crtc, BITS32 mask) { RegionPtr ret, crtc_region; BoxRec crtc_box; /* XXX CopyGC(src, dst, mask); */ CopyGC(src, dst, -1); miRegionDestroy(crtc_region); ValidateGC(crtc->pixmap, dst); } static Bool rrmx_simple_drawable(DrawablePtr pDraw) { ScreenPtr pScreen = pDraw->pScreen; rrScrPrivPtr rr = rrGetScrPriv(pScreen); /* Only one CRTC is simple */ if (rr->numCrtcs == 1) return TRUE; /* Only one CRTC allocation is simple */ if (rr->crtcs[0]->pixmap == NULL) return TRUE; if (pDraw->type == DRAWABLE_WINDOW) { WindowPtr pWin = (WindowPtr)pDraw; /* Windows with redirected storage are simple */ if (pWin->redirectDraw != RedirectDrawNone) return TRUE; /* * Window only on one CRTC is simple too, but you don't want to * expose that straight to the driver. Not a big deal though, * we'll only dispatch to the CRTCs we're actually on, see * rrmx_translate_gc. */ } else { /* Buffers that aren't shattered root storage are simple */ mx_screen_private *mxs = rrmx_get_screen_private(pScreen); if (pDraw != mxs->shattered_root) return TRUE; } return FALSE; } static Bool rrmx_on_same_crtc(DrawablePtr pSrc, DrawablePtr pDst, RRCrtcPtr *out_crtc) { rrScrPrivPtr rr = rrGetScrPriv(pSrc->pScreen); BoxRec crtc_box, src_box, dst_box; int i; /* This shouldn't ever happen, but if it does, assume the worst */ if ((pSrc->type != DRAWABLE_WINDOW) || (pDst->type != DRAWABLE_WINDOW)) return FALSE; rrmx_box(&src_box, pSrc->x, pSrc->y, pSrc->width, pSrc->height); rrmx_box(&dst_box, pDst->x, pDst->y, pDst->width, pDst->height); for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crts[i]; rrmx_box(&crtc_box, crtc->x, crtc->y, crtc->mode->mode->width, crtc->mode->mode->height); if (SUBSUMES(&crtc_box, &src_box) && SUBSUMES(&crtc_box, &dst_box)) { *out_crtc = crtc; return TRUE; } } return FALSE; } /*** GC ops ***/ /* XXX shouldn't ever happen */ static void rrmx_fill_spans(DrawablePtr pDraw, GCPtr pGC, int nInit, DDXPointPtr pptInit, int *widthInit, int sorted) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->FillSpans = mxg->wrap->FillSpans; if (rrmx_simple_drawable(pDraw)) { pGC->ops->FillSpans(pDraw, pGC, nInit, pptInit, widthInit, sorted); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; DDXPointPtr *points = NULL; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; if (!(rrmx_copy_points(&points, nInit, pptInit))) continue; pGC->ops->FillSpans(crtc->pixmap, scratch_gc, nInit, points, widthInit, sorted); } if (points) xfree(points); FreeScratchGC(scratch_gc); } pGC->ops->FillSpans = rrmx_fill_spans; } /* XXX shouldn't ever happen */ static void rrmx_set_spans(DrawablePtr pDraw, GCPtr pGC, char *src, DDXPointPtr ppt, int *width, int nspans, int sorted) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->SetSpans = mxg->wrap->SetSpans; if (rrmx_simple_drawable(pDraw)) { pGC->ops->SetSpans(pDraw, pGC, nInit, src, ppt, width, nspans, sorted); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; DDXPointPtr *points = NULL; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; if (!(rrmx_copy_points(&points, nspans, ppt))) continue; pGC->ops->SetSpans(crtc->pixmap, scratch_gc, src, points, width, nspans, sorted); } if (points) xfree(points); FreeScratchGC(scratch_gc); } pGC->ops->FillSpans = rrmx_fill_spans; } static void rrmx_put_image(DrawablePtr pDraw, GCPtr pGC, int depth, int x, int y, int w, int h, int pad, int format, char *bits) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PutImage = mxg->wrap->PutImage; if (rrmx_simple_drawable(pDraw)) { pGC->ops->PutImage(pDraw, pGC, depth, x, y, w, h, pad, format, bits); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; pGC->ops->PutImage(crtc->pixmap, scratch_gc, depth, x, y, w, h, pad, format, bits); } FreeScratchGC(scratch_gc); } pGC->ops->PutImage = rrmx_put_image; } static RegionPtr rrmx_copy_area(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); Bool simple_src = rrmx_simple_drawable(pSrc); Bool simple_dst = rrmx_simple_drawable(pDst); GCPtr scratch_gc = NULL; RRCrtcPtr crtc; int i, j; pGC->ops->CopyArea = mxg->wrap->CopyArea; if (simple_src && simple_dst) { pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); } else if (simple_src) { scratch_gc = GetScratchGC(pGC->depth, pScreen); for (i = 0; i < rr->numCrtcs; i++) { crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; pGC->ops->CopyArea(pSrc, crtc->pixmap, scratch_gc, srcx, srcy, w, h, dstx, dsty); } } else if (simple_dst) { scratch_gc = GetScratchGC(pGC->depth, pScreen); for (i = 0; i < rr->numCrtcs; i++) { crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; pGC->ops->CopyArea(crtc->pixmap, pDst, scratch_gc, srcx, srcy, w, h, dstx, dsty); } } else if (rrmx_on_same_crtc(pSrc, pDst, &crtc)) { scratch_gc = GetScratchGC(pGC->depth, pScreen); rrmx_translate_gc(scratch_gc, pGC, crtc, -1); pGC->ops->CopyArea(crtc->pixmap, crtc->pixmap, scratch_gc, srcx, srcy, w, h, dstx, dsty); } else { /* Full general case of despair */ RRCrtcPtr src_crtc, dst_crtc; for (i = 0; i < rr->numCrts); } if (scratch_gc) FreeScratchGC(scratch_gc); pGC->ops->CopyArea = rrmx_copy_area; } static RegionPtr rrmx_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty, unsigned long bitplane) { } static void rrmx_poly_point(DrawablePtr pDraw, GCPtr pGC, int mode, int n, DDXPointPtr pptInit) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PolyPoint = mxg->wrap->PolyPoint; if (rrmx_simple_drawable(pDraw)) { pGC->ops->PolyPoint(pDraw, pGC, mode, n, pptInit); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; DDXPointPtr points = NULL; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; if (!(rrmx_copy_points(&points, n, pptInit))) continue; pGC->ops->PolyPoint(crtc->pixmap, scratch_gc, mode, n, points); } if (points) xfree(points); FreeScratchGC(scratch_gc); } pGC->ops->PolyPoint = rrmx_poly_point; } static void rrmx_poly_lines(DrawablePtr pDraw, GCPtr pGC, int mode, int n, DDXPointPtr pptInit) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->Polylines = mxg->wrap->Polylines; if (rrmx_simple_drawable(pDraw)) { pGC->ops->Polylines(pDraw, pGC, mode, n, pptInit); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; DDXPointPtr points = NULL; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; if (!(rrmx_copy_points(&points, n, pptInit))) continue; pGC->ops->Polylines(crtc->pixmap, scratch_gc, mode, n, points); } if (points) xfree(points); FreeScratchGC(scratch_gc); } pGC->ops->Polylines = rrmx_poly_lines; } static void rrmx_poly_segment(DrawablePtr pDraw, GCPtr pGC, int n, xSegment *segs) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PolySegment = mxg->wrap->PolySegment; if (rrmx_simple_drawable(pDraw)) { pGC->ops->PolySegment(pDraw, pGC, n, segs); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; xSegment *seg = NULL; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; if (!(rrmx_copy_segments(&seg, n, segs))) continue; pGC->ops->PolySegment(crtc->pixmap, scratch_gc, n, seg); } if (seg) xfree(seg); FreeScratchGC(scratch_gc); } pGC->ops->PolySegment = rrmx_poly_segment; } static void rrmx_poly_rectangle(DrawablePtr pDraw, GCPtr pGC, int n, xRectangle *rects) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PolyRectangle = mxg->wrap->PolyRectangle; if (rrmx_simple_drawable(pDraw)) { pGC->ops->PolyRectangle(pDraw, pGC, n, rects); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; xRectangle *rect = NULL; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; if (!(rrmx_copy_rectangles(&rect, n, rects))) continue; pGC->ops->PolyRectangle(crtc->pixmap, scratch_gc, n, rect); } if (rect) xfree(rect); FreeScratchGC(scratch_gc); } pGC->ops->PolyRectangle = rrmx_poly_rectangle; } static void rrmx_poly_arc(DrawablePtr pDraw, GCPtr pGC, int n, xArc *arcs) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PolyArc = mxg->wrap->PolyArc; if (rrmx_simple_drawable(pDraw)) { pGC->ops->PolyArc(pDraw, pGC, n, rects); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; xArc *arc = NULL; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; if (!(rrmx_copy_arcs(&arc, n, arcs))) continue; pGC->ops->PolyArc(crtc->pixmap, scratch_gc, n, arc); } if (arc) xfree(arc); FreeScratchGC(scratch_gc); } pGC->ops->PolyArc = rrmx_poly_arc; } static void rrmx_fill_polygon(DrawablePtr pDraw, GCPtr pGC, int shape, int mode, int count, DDXPointPtr pts) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->FillPolygon = mxg->wrap->FillPolygon; if (rrmx_simple_drawable(pDraw)) { pGC->ops->FillPolygon(pDraw, pGC, shape, mode, count, pts); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; DDXPointPtr *points = NULL; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; if (!(rrmx_copy_points(&points, count, pts))) continue; pGC->ops->FillPolygon(crtc->pixmap, scratch_gc, shape, mode, count, pts); } if (point) xfree(points); FreeScratchGC(scratch_gc); } pGC->ops->FillPolygon = rrmx_fill_polygon; } static void rrmx_poly_fill_rect(DrawablePtr pDraw, GCPtr pGC, int n, xRectangle *rectInit) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PolyFillRect = mxg->wrap->PolyFillRect; if (rrmx_simple_drawable(pDraw)) { pGC->ops->PolyFillRect(pDraw, pGC, n, rectInit); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; xRectangle *rect = NULL; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; if (!(rrmx_copy_rectangles(&rect, n, rectInit))) continue; pGC->ops->PolyFillRect(crtc->pixmap, scratch_gc, n, rect); } if (rect) xfree(rect); FreeScratchGC(scratch_gc); } pGC->ops->PolyFillRect = rrmx_poly_fill_rect; } static void rrmx_poly_fill_arc(DrawablePtr pDraw, GCPtr pGC, int n, xArc *arcs) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PolyFillArc = mxg->wrap->PolyFillArc; if (rrmx_simple_drawable(pDraw)) { pGC->ops->PolyFillArc(pDraw, pGC, n, arcs); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; xArc *arc = NULL; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; if (!(rrmx_copy_arcs(&arc, n, arcs))) continue; pGC->ops->PolyFillArc(crtc->pixmap, scratch_gc, n, arc); } if (arc) xfree(arc); FreeScratchGC(scratch_gc); } pGC->ops->PolyFillArc = rrmx_poly_fill_arc; } static void rrmx_poly_text8(DrawablePtr pDraw, GCPtr pGC, int x, int y, int n, char *chars) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PolyText8 = mxg->wrap->PolyText8; if (rrmx_simple_drawable(pDraw)) { pGC->ops->PolyText8(pDraw, pGC, x, y, n, chars); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; pGC->ops->PolyText8(crtc->pixmap, scratch_gc, x, y, n, chars); } FreeScratchGC(scratch_gc); } pGC->ops->PolyText8 = rrmx_poly_text8; } static void rrmx_poly_text16(DrawablePtr pDraw, GCPtr pGC, int x, int y, int n, unsigned short *chars) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PolyText16 = mxg->wrap->PolyText16; if (rrmx_simple_drawable(pDraw)) { pGC->ops->PolyText16(pDraw, pGC, x, y, n, chars); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; pGC->ops->PolyText16(crtc->pixmap, scratch_gc, x, y, n, chars); } FreeScratchGC(scratch_gc); } pGC->ops->PolyText16 = rrmx_poly_text16; } static void rrmx_image_text8(DrawablePtr pDraw, GCPtr pGC, int x, int y, int n, char *chars) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->ImageText8 = mxg->wrap->ImageText8; if (rrmx_simple_drawable(pDraw)) { pGC->ops->ImageText8(pDraw, pGC, x, y, n, chars); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; pGC->ops->ImageText8(crtc->pixmap, scratch_gc, x, y, n, chars); } FreeScratchGC(scratch_gc); } pGC->ops->ImageText8 = rrmx_image_text8; } static void rrmx_image_text16(DrawablePtr pDraw, GCPtr pGC, int x, int y, int n, unsigned short *chars) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->ImageText16 = mxg->wrap->ImageText16; if (rrmx_simple_drawable(pDraw)) { pGC->ops->ImageText16(pDraw, pGC, x, y, n, chars); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; pGC->ops->ImageText16(crtc->pixmap, scratch_gc, x, y, n, chars); } FreeScratchGC(scratch_gc); } pGC->ops->ImageText16 = rrmx_image_text16; } static void rrmx_image_glyph_blt(DrawablePtr pDraw, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, void *base) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->ImageGlyphBlt = mxg->wrap->ImageGlyphBlt; if (rrmx_simple_drawable(pDraw)) { pGC->ops->ImageGlyphBlt(pDraw, pGC, x, y, nglyph, ppci, base); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; pGC->ops->ImageGlyphBlt(crtc->pixmap, scratch_gc, x, y, nglyph, ppci, base); } FreeScratchGC(scratch_gc); } pGC->ops->ImageGlyphBlt = rrmx_image_glyph_blt; } static void rrmx_poly_glyph_blt(DrawablePtr pDraw, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, void *base) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PolyGlyphBlt = mxg->wrap->PolyGlyphBlt; if (rrmx_simple_drawable(pDraw)) { pGC->ops->PolyGlyphBlt(pDraw, pGC, x, y, n, chars); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; pGC->ops->PolyGlyphBlt(crtc->pixmap, scratch_gc, x, y, nglyph, ppci, base); } FreeScratchGC(scratch_gc); } pGC->ops->PolyGlyphBlt = rrmx_poly_glyph_blt; } /* XXX shouldn't ever happen */ static void rrmx_push_pixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst, int w, int h, int x, int y) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); pGC->ops->PushPixels = mxg->wrap->PushPixels; if (rrmx_simple_drawable(pDst)) { pGC->ops->PushPixels(pGC, pBitMap, pDst, w, h, x, y); } else { GCPtr scratch_gc = GetScratchGC(pGC->depth, pScreen); int i; for (i = 0; i < rr->numCrtcs; i++) { RRCrtcPtr crtc = rr->crtcs[i]; if (!rrmx_translate_gc(scratch_gc, pGC, crtc, -1)) continue; pGC->ops->PushPixels(scratch_gc, pBitMap, crtc->pixmap, w, h, x, y); } FreeScratchGC(scratch_gc); } pGC->ops->PushPixels = rrmx_push_pixels; } static GCOps rrmx_ops = { rrmx_fill_spans, rrmx_set_spans, rrmx_put_image, rrmx_copy_area, rrmx_copy_plane, rrmx_poly_point, rrmx_poly_lines, rrmx_poly_segment, rrmx_poly_rectangle, rrmx_poly_arc, rrmx_fill_polygon, rrmx_poly_fill_rect, rrmx_poly_fill_arc, rrmx_poly_text8, rrmx_poly_text16, rrmx_image_text8, rrmx_image_text16, rrmx_image_glyph_blt, rrmx_poly_glyph_blt, rrmx_push_pixels, }; /*** GC Funcs ***/ static void rrmx_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDraw) { ScreenPtr pScreen = pGC->pScreen; mx_gc_private *mxg = rrmx_get_gc_private(pGC); rrScrPrivPtr rr = rrGetScrPriv(pScreen); /* we rely on the underlying layers to compute the composite clip */ pGC->funcs->ValidateGC = mxg->funcs->ValidateGC; pGC->funcs->ValidateGC(pGC, changes, pDraw); /* * Only insert into the dispatch chain if there could be more than one * CRTC pixmap. */ if (rr->numCrtcs > 1) { mxg->wrap = pGC->ops; pGC->ops = &rrmxOps; } pGC->funcs->ValidateGC = rrmx_validate_gc; } static void rrmx_change_gc(GCPtr pGC, unsigned long mask) { mx_gc_private *mxg = rrmx_get_gc_private(pGC); pGC->funcs->ChangeGC = mxg->funcs->ChangeGC; pGC->funcs->ChangeGC(pGC, mask); pGC->funcs->ChangeGC = rrmx_change_gc; } static void rrmx_copy_gc(GCPtr src, unsigned long mask, GCPtr dst) { mx_gc_private *mxg = rrmx_get_gc_private(pGC); pGC->funcs->CopyGC = mxg->funcs->CopyGC; pGC->funcs->CopyGC(src, mask, dst); pGC->funcs->CopyGC = rrmx_copy_gc; } static void rrmx_destroy_gc(GCPtr pGC) { mx_gc_private *mxg = rrmx_get_gc_private(pGC); pGC->funcs->DestroyGC = mxg->funcs->DestroyGC; pGC->funcs->DestroyGC(pGC); pGC->funcs->DestroyGC = rrmx_destroy_gc; } static void rrmx_change_clip(GCPtr pGC, int type, void *value, int nrects) { mx_gc_private *mxg = rrmx_get_gc_private(pGC); pGC->funcs->ChangeClip = mxg->funcs->ChangeClip; pGC->funcs->ChangeClip(pGC, type, value, nrects); pGC->funcs->ChangeClip = rrmx_change_clip; } static void rrmx_destroy_clip(GCPtr pGC) { mx_gc_private *mxg = rrmx_get_gc_private(pGC); pGC->funcs->DestroyClip = mxg->funcs->DestroyClip; pGC->funcs->DestroyClip(pGC); pGC->funcs->DestroyClip = rrmx_destroy_clip; } static void rrmx_copy_clip(GCPtr dst, GCPtr src) { mx_gc_private *mxg = rrmx_get_gc_private(pGC); pGC->funcs->CopyClip = mxg->funcs->CopyClip; pGC->funcs->CopyClip(dst, src); pGC->funcs->CopyClip = rrmx_copy_clip; } static GCFuncs rrmx_gc_funcs = { rrmx_validate_gc, rrmx_change_gc, rrmx_copy_gc, rrmx_destroy_gc, rrmx_change_clip, rrmx_destroy_clip, rrmx_copy_clip }; /*** Screen hooks ***/ static Bool rrmxCreateGC(GCPtr pGC) { ScreenPtr pScreen = pGC->pScreen; mx_screen_private *mxs = rrmx_get_screen_private(pScreen); mx_gc_private *mxg = rrmx_get_gc_private(pScreen); Bool ret; pScreen->CreateGC = mxs->CreateGC; ret = pScreen->CreateGC(pGC); if (!ret) return FALSE; mxg->funcs = pGC->funcs; pGC->funcs = rrmx_gc_funcs; pScreen->CreateGC = rrmxCreateGC; return ret; } /*** Public interface ***/ /* * XXX this probably should be an export, just silently enabled, and if * the driver ever sets a CRTC pixmap we'll just insert ourselves into * rendering dispatch. */ _X_EXPORT Bool rrmxScreenInit(ScreenPtr pScreen) { mx_screen_private *mxs; if (rrmxGeneration != serverGeneration) { rrmxScreenPrivateIndex = AllocateScreenPrivateIndex(); rrmxGCPrivateIndex = AllocateGCPrivateIndex(); /* other */ rrmxGeneration = serverGeneration; } /* allocate privates */ /* screen hooks */ mxs->CreateGC = pScreen->CreateGC; pScreen->CreateGC = rrmxCreateGC; /* gc hookery */ #ifdef MITSHM /* hook shm funcs */ #endif ps = GetPictureScreenIfSet(); if (ps) { /* render hookery */ } #ifdef XV /* stuff */ #endif return TRUE; } _X_EXPORT void rrmxScreenFini(ScreenPtr pScreen) { }