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
346747b715Smrg/* This file holds the classic exa specific implementation. */
356747b715Smrg
3635c4bbdfSmrgstatic _X_INLINE void *
376747b715SmrgExaGetPixmapAddress(PixmapPtr p)
386747b715Smrg{
396747b715Smrg    ExaPixmapPriv(p);
406747b715Smrg
416747b715Smrg    if (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr)
4235c4bbdfSmrg        return pExaPixmap->fb_ptr;
436747b715Smrg    else
4435c4bbdfSmrg        return pExaPixmap->sys_ptr;
456747b715Smrg}
466747b715Smrg
476747b715Smrg/**
486747b715Smrg * exaCreatePixmap() creates a new pixmap.
496747b715Smrg *
506747b715Smrg * If width and height are 0, this won't be a full-fledged pixmap and it will
516747b715Smrg * get ModifyPixmapHeader() called on it later.  So, we mark it as pinned, because
526747b715Smrg * ModifyPixmapHeader() would break migration.  These types of pixmaps are used
536747b715Smrg * for scratch pixmaps, or to represent the visible screen.
546747b715Smrg */
556747b715SmrgPixmapPtr
566747b715SmrgexaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
5735c4bbdfSmrg                        unsigned usage_hint)
586747b715Smrg{
596747b715Smrg    PixmapPtr pPixmap;
6035c4bbdfSmrg    ExaPixmapPrivPtr pExaPixmap;
616747b715Smrg    BoxRec box;
626747b715Smrg    int bpp;
6335c4bbdfSmrg
646747b715Smrg    ExaScreenPriv(pScreen);
656747b715Smrg
666747b715Smrg    if (w > 32767 || h > 32767)
6735c4bbdfSmrg        return NullPixmap;
686747b715Smrg
696747b715Smrg    swap(pExaScr, pScreen, CreatePixmap);
7035c4bbdfSmrg    pPixmap = pScreen->CreatePixmap(pScreen, w, h, depth, usage_hint);
716747b715Smrg    swap(pExaScr, pScreen, CreatePixmap);
726747b715Smrg
736747b715Smrg    if (!pPixmap)
746747b715Smrg        return NULL;
756747b715Smrg
766747b715Smrg    pExaPixmap = ExaGetPixmapPriv(pPixmap);
776747b715Smrg    pExaPixmap->driverPriv = NULL;
786747b715Smrg
796747b715Smrg    bpp = pPixmap->drawable.bitsPerPixel;
806747b715Smrg
816747b715Smrg    pExaPixmap->driverPriv = NULL;
826747b715Smrg    /* Scratch pixmaps may have w/h equal to zero, and may not be
836747b715Smrg     * migrated.
846747b715Smrg     */
856747b715Smrg    if (!w || !h)
8635c4bbdfSmrg        pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
876747b715Smrg    else
8835c4bbdfSmrg        pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
896747b715Smrg
906747b715Smrg    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
916747b715Smrg    pExaPixmap->sys_pitch = pPixmap->devKind;
926747b715Smrg
936747b715Smrg    pPixmap->devPrivate.ptr = NULL;
946747b715Smrg    pExaPixmap->use_gpu_copy = FALSE;
956747b715Smrg
966747b715Smrg    pExaPixmap->fb_ptr = NULL;
976747b715Smrg    exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
986747b715Smrg    pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
996747b715Smrg
1006747b715Smrg    if (pExaPixmap->fb_pitch > 131071) {
10135c4bbdfSmrg        swap(pExaScr, pScreen, DestroyPixmap);
10235c4bbdfSmrg        pScreen->DestroyPixmap(pPixmap);
10335c4bbdfSmrg        swap(pExaScr, pScreen, DestroyPixmap);
10435c4bbdfSmrg        return NULL;
1056747b715Smrg    }
1066747b715Smrg
1076747b715Smrg    /* Set up damage tracking */
10835c4bbdfSmrg    pExaPixmap->pDamage = DamageCreate(NULL, NULL,
10935c4bbdfSmrg                                       DamageReportNone, TRUE,
11035c4bbdfSmrg                                       pScreen, pPixmap);
1116747b715Smrg
1126747b715Smrg    if (pExaPixmap->pDamage == NULL) {
11335c4bbdfSmrg        swap(pExaScr, pScreen, DestroyPixmap);
11435c4bbdfSmrg        pScreen->DestroyPixmap(pPixmap);
11535c4bbdfSmrg        swap(pExaScr, pScreen, DestroyPixmap);
11635c4bbdfSmrg        return NULL;
1176747b715Smrg    }
1186747b715Smrg
11935c4bbdfSmrg    DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
1206747b715Smrg    /* This ensures that pending damage reflects the current operation. */
1216747b715Smrg    /* This is used by exa to optimize migration. */
12235c4bbdfSmrg    DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
1236747b715Smrg
1246747b715Smrg    pExaPixmap->area = NULL;
1256747b715Smrg
1266747b715Smrg    /* We set the initial pixmap as completely valid for a simple reason.
1276747b715Smrg     * Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which
1286747b715Smrg     * could form single pixel rects as part of a region. Setting the complete region
1296747b715Smrg     * as valid is a natural defragmentation of the region.
1306747b715Smrg     */
1316747b715Smrg    box.x1 = 0;
1326747b715Smrg    box.y1 = 0;
1336747b715Smrg    box.x2 = w;
1346747b715Smrg    box.y2 = h;
1356747b715Smrg    RegionInit(&pExaPixmap->validSys, &box, 0);
1366747b715Smrg    RegionInit(&pExaPixmap->validFB, &box, 0);
1376747b715Smrg
13835c4bbdfSmrg    exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
1396747b715Smrg
1406747b715Smrg    /* During a fallback we must prepare access. */
1416747b715Smrg    if (pExaScr->fallback_counter)
14235c4bbdfSmrg        exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
1436747b715Smrg
1446747b715Smrg    return pPixmap;
1456747b715Smrg}
1466747b715Smrg
1476747b715SmrgBool
14835c4bbdfSmrgexaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height,
14935c4bbdfSmrg                              int depth, int bitsPerPixel, int devKind,
15035c4bbdfSmrg                              void *pPixData)
1516747b715Smrg{
1526747b715Smrg    ScreenPtr pScreen;
1536747b715Smrg    ExaScreenPrivPtr pExaScr;
1546747b715Smrg    ExaPixmapPrivPtr pExaPixmap;
1556747b715Smrg    Bool ret;
1566747b715Smrg
1576747b715Smrg    if (!pPixmap)
1586747b715Smrg        return FALSE;
1596747b715Smrg
1606747b715Smrg    pScreen = pPixmap->drawable.pScreen;
1616747b715Smrg    pExaScr = ExaGetScreenPriv(pScreen);
1626747b715Smrg    pExaPixmap = ExaGetPixmapPriv(pPixmap);
1636747b715Smrg
1646747b715Smrg    if (pExaPixmap) {
1656747b715Smrg        if (pPixData)
1666747b715Smrg            pExaPixmap->sys_ptr = pPixData;
1676747b715Smrg
1686747b715Smrg        if (devKind > 0)
1696747b715Smrg            pExaPixmap->sys_pitch = devKind;
1706747b715Smrg
17135c4bbdfSmrg        /* Classic EXA:
17235c4bbdfSmrg         * - Framebuffer.
17335c4bbdfSmrg         * - Scratch pixmap with gpu memory.
17435c4bbdfSmrg         */
17535c4bbdfSmrg        if (pExaScr->info->memoryBase && pPixData) {
17635c4bbdfSmrg            if ((CARD8 *) pPixData >= pExaScr->info->memoryBase &&
17735c4bbdfSmrg                ((CARD8 *) pPixData - pExaScr->info->memoryBase) <
17835c4bbdfSmrg                pExaScr->info->memorySize) {
17935c4bbdfSmrg                pExaPixmap->fb_ptr = pPixData;
18035c4bbdfSmrg                pExaPixmap->fb_pitch = devKind;
18135c4bbdfSmrg                pExaPixmap->use_gpu_copy = TRUE;
18235c4bbdfSmrg            }
18335c4bbdfSmrg        }
1846747b715Smrg
1856747b715Smrg        if (width > 0 && height > 0 && bitsPerPixel > 0) {
18635c4bbdfSmrg            exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
1876747b715Smrg
18835c4bbdfSmrg            exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
1896747b715Smrg        }
1906747b715Smrg
19135c4bbdfSmrg        /* Pixmaps subject to ModifyPixmapHeader will be pinned to system or
19235c4bbdfSmrg         * gpu memory, so there's no need to track damage.
19335c4bbdfSmrg         */
19435c4bbdfSmrg        if (pExaPixmap->pDamage) {
19535c4bbdfSmrg            DamageDestroy(pExaPixmap->pDamage);
19635c4bbdfSmrg            pExaPixmap->pDamage = NULL;
19735c4bbdfSmrg        }
1986747b715Smrg    }
1996747b715Smrg
2006747b715Smrg    swap(pExaScr, pScreen, ModifyPixmapHeader);
2016747b715Smrg    ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
20235c4bbdfSmrg                                      bitsPerPixel, devKind, pPixData);
2036747b715Smrg    swap(pExaScr, pScreen, ModifyPixmapHeader);
2046747b715Smrg
2056747b715Smrg    /* Always NULL this, we don't want lingering pointers. */
2066747b715Smrg    pPixmap->devPrivate.ptr = NULL;
2076747b715Smrg
2086747b715Smrg    return ret;
2096747b715Smrg}
2106747b715Smrg
2116747b715SmrgBool
21235c4bbdfSmrgexaDestroyPixmap_classic(PixmapPtr pPixmap)
2136747b715Smrg{
21435c4bbdfSmrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
21535c4bbdfSmrg
2166747b715Smrg    ExaScreenPriv(pScreen);
2176747b715Smrg    Bool ret;
2186747b715Smrg
21935c4bbdfSmrg    if (pPixmap->refcnt == 1) {
22035c4bbdfSmrg        ExaPixmapPriv(pPixmap);
22135c4bbdfSmrg
22235c4bbdfSmrg        exaDestroyPixmap(pPixmap);
22335c4bbdfSmrg
22435c4bbdfSmrg        if (pExaPixmap->area) {
22535c4bbdfSmrg            DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
22635c4bbdfSmrg                        (void *) pPixmap->drawable.id,
22735c4bbdfSmrg                        ExaGetPixmapPriv(pPixmap)->area->offset,
22835c4bbdfSmrg                        pPixmap->drawable.width, pPixmap->drawable.height));
22935c4bbdfSmrg            /* Free the offscreen area */
23035c4bbdfSmrg            exaOffscreenFree(pPixmap->drawable.pScreen, pExaPixmap->area);
23135c4bbdfSmrg            pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
23235c4bbdfSmrg            pPixmap->devKind = pExaPixmap->sys_pitch;
23335c4bbdfSmrg        }
23435c4bbdfSmrg        RegionUninit(&pExaPixmap->validSys);
23535c4bbdfSmrg        RegionUninit(&pExaPixmap->validFB);
2366747b715Smrg    }
2376747b715Smrg
2386747b715Smrg    swap(pExaScr, pScreen, DestroyPixmap);
23935c4bbdfSmrg    ret = pScreen->DestroyPixmap(pPixmap);
2406747b715Smrg    swap(pExaScr, pScreen, DestroyPixmap);
2416747b715Smrg
2426747b715Smrg    return ret;
2436747b715Smrg}
2446747b715Smrg
2456747b715SmrgBool
2466747b715SmrgexaPixmapHasGpuCopy_classic(PixmapPtr pPixmap)
2476747b715Smrg{
2486747b715Smrg    ScreenPtr pScreen = pPixmap->drawable.pScreen;
24935c4bbdfSmrg
2506747b715Smrg    ExaScreenPriv(pScreen);
2516747b715Smrg    ExaPixmapPriv(pPixmap);
2526747b715Smrg    Bool ret;
2536747b715Smrg
2546747b715Smrg    if (pExaScr->info->PixmapIsOffscreen) {
25535c4bbdfSmrg        void *old_ptr = pPixmap->devPrivate.ptr;
25635c4bbdfSmrg
25735c4bbdfSmrg        pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
25835c4bbdfSmrg        ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
25935c4bbdfSmrg        pPixmap->devPrivate.ptr = old_ptr;
26035c4bbdfSmrg    }
26135c4bbdfSmrg    else
26235c4bbdfSmrg        ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr);
2636747b715Smrg
2646747b715Smrg    return ret;
2656747b715Smrg}
266