16747b715Smrg/*
235c4bbdfSmrg * Copyright © 2009 Maarten Maathuis
36747b715Smrg *
46747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a
56747b715Smrg * copy of this software and associated documentation files (the "Software"),
66747b715Smrg * to deal in the Software without restriction, including without limitation
76747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
86747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
96747b715Smrg * Software is furnished to do so, subject to the following conditions:
106747b715Smrg *
116747b715Smrg * The above copyright notice and this permission notice (including the next
126747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
136747b715Smrg * Software.
146747b715Smrg *
156747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
176747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
186747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
196747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
206747b715Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
216747b715Smrg * SOFTWARE.
226747b715Smrg *
236747b715Smrg */
246747b715Smrg
256747b715Smrg#ifdef HAVE_DIX_CONFIG_H
266747b715Smrg#include <dix-config.h>
276747b715Smrg#endif
286747b715Smrg
296747b715Smrg#include <string.h>
306747b715Smrg
316747b715Smrg#include "exa_priv.h"
326747b715Smrg#include "exa.h"
336747b715Smrg
346747b715Smrgvoid
356747b715SmrgexaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
366747b715Smrg{
376747b715Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
3835c4bbdfSmrg
396747b715Smrg    ExaScreenPriv(pScreen);
406747b715Smrg    ExaPixmapPriv(pPixmap);
416747b715Smrg    int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
426747b715Smrg    int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
436747b715Smrg    int usage_hint = pPixmap->usage_hint;
446747b715Smrg    int paddedWidth = pExaPixmap->sys_pitch;
456747b715Smrg
466747b715Smrg    /* Already done. */
476747b715Smrg    if (pExaPixmap->driverPriv)
4835c4bbdfSmrg        return;
496747b715Smrg
506747b715Smrg    if (exaPixmapIsPinned(pPixmap))
5135c4bbdfSmrg        return;
526747b715Smrg
536747b715Smrg    /* Can't accel 1/4 bpp. */
546747b715Smrg    if (pExaPixmap->accel_blocked || bpp < 8)
5535c4bbdfSmrg        return;
566747b715Smrg
576747b715Smrg    if (pExaScr->info->CreatePixmap2) {
5835c4bbdfSmrg        int new_pitch = 0;
5935c4bbdfSmrg
6035c4bbdfSmrg        pExaPixmap->driverPriv =
6135c4bbdfSmrg            pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp,
6235c4bbdfSmrg                                         &new_pitch);
6335c4bbdfSmrg        paddedWidth = pExaPixmap->fb_pitch = new_pitch;
6435c4bbdfSmrg    }
6535c4bbdfSmrg    else {
6635c4bbdfSmrg        if (paddedWidth < pExaPixmap->fb_pitch)
6735c4bbdfSmrg            paddedWidth = pExaPixmap->fb_pitch;
6835c4bbdfSmrg        pExaPixmap->driverPriv =
6935c4bbdfSmrg            pExaScr->info->CreatePixmap(pScreen, paddedWidth * h, 0);
706747b715Smrg    }
716747b715Smrg
726747b715Smrg    if (!pExaPixmap->driverPriv)
7335c4bbdfSmrg        return;
746747b715Smrg
7535c4bbdfSmrg    (*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
766747b715Smrg}
776747b715Smrg
786747b715Smrgvoid
796747b715SmrgexaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
806747b715Smrg{
816747b715Smrg    int i;
826747b715Smrg
836747b715Smrg    /* If anything is pinned in system memory, we won't be able to
846747b715Smrg     * accelerate.
856747b715Smrg     */
866747b715Smrg    for (i = 0; i < npixmaps; i++) {
8735c4bbdfSmrg        if (exaPixmapIsPinned(pixmaps[i].pPix) &&
8835c4bbdfSmrg            !exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
8935c4bbdfSmrg            can_accel = FALSE;
9035c4bbdfSmrg            break;
9135c4bbdfSmrg        }
926747b715Smrg    }
936747b715Smrg
946747b715Smrg    /* We can do nothing. */
956747b715Smrg    if (!can_accel)
9635c4bbdfSmrg        return;
976747b715Smrg
986747b715Smrg    for (i = 0; i < npixmaps; i++) {
9935c4bbdfSmrg        PixmapPtr pPixmap = pixmaps[i].pPix;
10035c4bbdfSmrg
10135c4bbdfSmrg        ExaPixmapPriv(pPixmap);
10235c4bbdfSmrg
10335c4bbdfSmrg        if (!pExaPixmap->driverPriv)
10435c4bbdfSmrg            exaCreateDriverPixmap_mixed(pPixmap);
10535c4bbdfSmrg
10635c4bbdfSmrg        if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) {
10735c4bbdfSmrg            ExaScreenPriv(pPixmap->drawable.pScreen);
10835c4bbdfSmrg
10935c4bbdfSmrg            /* This pitch is needed for proper acceleration. For some reason
11035c4bbdfSmrg             * there are pixmaps without pDamage and a bad fb_pitch value.
11135c4bbdfSmrg             * So setting devKind when only exaPixmapHasGpuCopy() is true
11235c4bbdfSmrg             * causes corruption. Pixmaps without pDamage are not migrated
11335c4bbdfSmrg             * and should have a valid devKind at all times, so that's why this
11435c4bbdfSmrg             * isn't causing problems. Pixmaps have their gpu pitch set the
11535c4bbdfSmrg             * first time in the MPH call from exaCreateDriverPixmap_mixed().
11635c4bbdfSmrg             */
11735c4bbdfSmrg            pPixmap->devKind = pExaPixmap->fb_pitch;
11835c4bbdfSmrg            exaCopyDirtyToFb(pixmaps + i);
11935c4bbdfSmrg
12035c4bbdfSmrg            if (pExaScr->deferred_mixed_pixmap == pPixmap &&
12135c4bbdfSmrg                !pixmaps[i].as_dst && !pixmaps[i].pReg)
12235c4bbdfSmrg                pExaScr->deferred_mixed_pixmap = NULL;
12335c4bbdfSmrg        }
12435c4bbdfSmrg
12535c4bbdfSmrg        pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
1266747b715Smrg    }
1276747b715Smrg}
1286747b715Smrg
1296747b715Smrgvoid
1306747b715SmrgexaMoveInPixmap_mixed(PixmapPtr pPixmap)
1316747b715Smrg{
1326747b715Smrg    ExaMigrationRec pixmaps[1];
1336747b715Smrg
1346747b715Smrg    pixmaps[0].as_dst = FALSE;
1356747b715Smrg    pixmaps[0].as_src = TRUE;
1366747b715Smrg    pixmaps[0].pPix = pPixmap;
1376747b715Smrg    pixmaps[0].pReg = NULL;
1386747b715Smrg
1396747b715Smrg    exaDoMigration(pixmaps, 1, TRUE);
1406747b715Smrg}
1416747b715Smrg
1426747b715Smrgvoid
1436747b715SmrgexaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure)
1446747b715Smrg{
1456747b715Smrg    PixmapPtr pPixmap = closure;
14635c4bbdfSmrg
1476747b715Smrg    ExaPixmapPriv(pPixmap);
1486747b715Smrg
1496747b715Smrg    /* Move back results of software rendering on system memory copy of mixed driver
1506747b715Smrg     * pixmap (see exaPrepareAccessReg_mixed).
1516747b715Smrg     *
1526747b715Smrg     * Defer moving the destination back into the driver pixmap, to try and save
1536747b715Smrg     * overhead on multiple subsequent software fallbacks.
1546747b715Smrg     */
1556747b715Smrg    if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) {
15635c4bbdfSmrg        ExaScreenPriv(pPixmap->drawable.pScreen);
1576747b715Smrg
15835c4bbdfSmrg        if (pExaScr->deferred_mixed_pixmap &&
15935c4bbdfSmrg            pExaScr->deferred_mixed_pixmap != pPixmap)
16035c4bbdfSmrg            exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
16135c4bbdfSmrg        pExaScr->deferred_mixed_pixmap = pPixmap;
1626747b715Smrg    }
1636747b715Smrg}
1646747b715Smrg
1656747b715Smrg/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
1666747b715Smrg * use the DownloadFromScreen hook to retrieve contents to a copy in system
1676747b715Smrg * memory, perform software rendering on that and move back the results with the
1686747b715Smrg * UploadToScreen hook (see exaDamageReport_mixed).
1696747b715Smrg */
1706747b715Smrgvoid
1716747b715SmrgexaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
1726747b715Smrg{
1736747b715Smrg    ExaPixmapPriv(pPixmap);
1746747b715Smrg    Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
1756747b715Smrg    Bool success;
1766747b715Smrg
1776747b715Smrg    success = ExaDoPrepareAccess(pPixmap, index);
1786747b715Smrg
1796747b715Smrg    if (success && has_gpu_copy && pExaPixmap->pDamage) {
18035c4bbdfSmrg        /* You cannot do accelerated operations while a buffer is mapped. */
18135c4bbdfSmrg        exaFinishAccess(&pPixmap->drawable, index);
18235c4bbdfSmrg        /* Update the gpu view of both deferred destination pixmaps and of
18335c4bbdfSmrg         * source pixmaps that were migrated with a bounding region.
18435c4bbdfSmrg         */
18535c4bbdfSmrg        exaMoveInPixmap_mixed(pPixmap);
18635c4bbdfSmrg        success = ExaDoPrepareAccess(pPixmap, index);
18735c4bbdfSmrg
18835c4bbdfSmrg        if (success) {
18935c4bbdfSmrg            /* We have a gpu pixmap that can be accessed, we don't need the cpu
19035c4bbdfSmrg             * copy anymore. Drivers that prefer DFS, should fail prepare
19135c4bbdfSmrg             * access.
19235c4bbdfSmrg             */
19335c4bbdfSmrg            DamageDestroy(pExaPixmap->pDamage);
19435c4bbdfSmrg            pExaPixmap->pDamage = NULL;
19535c4bbdfSmrg
19635c4bbdfSmrg            free(pExaPixmap->sys_ptr);
19735c4bbdfSmrg            pExaPixmap->sys_ptr = NULL;
19835c4bbdfSmrg
19935c4bbdfSmrg            return;
20035c4bbdfSmrg        }
2016747b715Smrg    }
2026747b715Smrg
2036747b715Smrg    if (!success) {
20435c4bbdfSmrg        ExaMigrationRec pixmaps[1];
20535c4bbdfSmrg
20635c4bbdfSmrg        /* Do we need to allocate our system buffer? */
20735c4bbdfSmrg        if (!pExaPixmap->sys_ptr) {
20835c4bbdfSmrg            pExaPixmap->sys_ptr = xallocarray(pExaPixmap->sys_pitch,
20935c4bbdfSmrg                                              pPixmap->drawable.height);
21035c4bbdfSmrg            if (!pExaPixmap->sys_ptr)
21135c4bbdfSmrg                FatalError("EXA: malloc failed for size %d bytes\n",
21235c4bbdfSmrg                           pExaPixmap->sys_pitch * pPixmap->drawable.height);
21335c4bbdfSmrg        }
21435c4bbdfSmrg
21535c4bbdfSmrg        if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
21635c4bbdfSmrg            pixmaps[0].as_dst = TRUE;
21735c4bbdfSmrg            pixmaps[0].as_src = FALSE;
21835c4bbdfSmrg        }
21935c4bbdfSmrg        else {
22035c4bbdfSmrg            pixmaps[0].as_dst = FALSE;
22135c4bbdfSmrg            pixmaps[0].as_src = TRUE;
22235c4bbdfSmrg        }
22335c4bbdfSmrg        pixmaps[0].pPix = pPixmap;
22435c4bbdfSmrg        pixmaps[0].pReg = pReg;
22535c4bbdfSmrg
22635c4bbdfSmrg        if (!pExaPixmap->pDamage &&
22735c4bbdfSmrg            (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) {
22835c4bbdfSmrg            Bool as_dst = pixmaps[0].as_dst;
22935c4bbdfSmrg
23035c4bbdfSmrg            /* Set up damage tracking */
23135c4bbdfSmrg            pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
23235c4bbdfSmrg                                               DamageReportNonEmpty, TRUE,
23335c4bbdfSmrg                                               pPixmap->drawable.pScreen,
23435c4bbdfSmrg                                               pPixmap);
23535c4bbdfSmrg
23635c4bbdfSmrg            if (pExaPixmap->pDamage) {
23735c4bbdfSmrg                DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
23835c4bbdfSmrg                /* This ensures that pending damage reflects the current
23935c4bbdfSmrg                 * operation. This is used by exa to optimize migration.
24035c4bbdfSmrg                 */
24135c4bbdfSmrg                DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
24235c4bbdfSmrg            }
24335c4bbdfSmrg
24435c4bbdfSmrg            if (has_gpu_copy) {
24535c4bbdfSmrg                exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
24635c4bbdfSmrg                               pPixmap->drawable.height);
24735c4bbdfSmrg
24835c4bbdfSmrg                /* We don't know which region of the destination will be damaged,
24935c4bbdfSmrg                 * have to assume all of it
25035c4bbdfSmrg                 */
25135c4bbdfSmrg                if (as_dst) {
25235c4bbdfSmrg                    pixmaps[0].as_dst = FALSE;
25335c4bbdfSmrg                    pixmaps[0].as_src = TRUE;
25435c4bbdfSmrg                    pixmaps[0].pReg = NULL;
25535c4bbdfSmrg                }
25635c4bbdfSmrg                exaCopyDirtyToSys(pixmaps);
25735c4bbdfSmrg            }
25835c4bbdfSmrg
25935c4bbdfSmrg            if (as_dst)
26035c4bbdfSmrg                exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
26135c4bbdfSmrg                               pPixmap->drawable.height);
26235c4bbdfSmrg        }
26335c4bbdfSmrg        else if (has_gpu_copy)
26435c4bbdfSmrg            exaCopyDirtyToSys(pixmaps);
26535c4bbdfSmrg
26635c4bbdfSmrg        pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
26735c4bbdfSmrg        pPixmap->devKind = pExaPixmap->sys_pitch;
26835c4bbdfSmrg        pExaPixmap->use_gpu_copy = FALSE;
2696747b715Smrg    }
2706747b715Smrg}
271