1/*
2 * Copyright � 2009 Maarten Maathuis
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 */
24
25#ifdef HAVE_DIX_CONFIG_H
26#include <dix-config.h>
27#endif
28
29#include <string.h>
30
31#include "exa_priv.h"
32#include "exa.h"
33
34/* This file holds the driver allocated pixmaps specific implementation. */
35
36static _X_INLINE void*
37ExaGetPixmapAddress(PixmapPtr p)
38{
39    ExaPixmapPriv(p);
40
41    return pExaPixmap->sys_ptr;
42}
43
44/**
45 * exaCreatePixmap() creates a new pixmap.
46 *
47 * Pixmaps are always marked as pinned, because exa has no control over them.
48 */
49PixmapPtr
50exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
51		unsigned usage_hint)
52{
53    PixmapPtr pPixmap;
54    ExaPixmapPrivPtr	pExaPixmap;
55    int bpp;
56    size_t paddedWidth, datasize;
57    ExaScreenPriv(pScreen);
58
59    if (w > 32767 || h > 32767)
60	return NullPixmap;
61
62    swap(pExaScr, pScreen, CreatePixmap);
63    pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
64    swap(pExaScr, pScreen, CreatePixmap);
65
66    if (!pPixmap)
67        return NULL;
68
69    pExaPixmap = ExaGetPixmapPriv(pPixmap);
70    pExaPixmap->driverPriv = NULL;
71
72    bpp = pPixmap->drawable.bitsPerPixel;
73
74    /* Set this before driver hooks, to allow for driver pixmaps without gpu
75     * memory to back it. These pixmaps have a valid pointer at all times.
76     */
77    pPixmap->devPrivate.ptr = NULL;
78
79    if (pExaScr->info->CreatePixmap2) {
80	int new_pitch = 0;
81	pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch);
82	paddedWidth = pExaPixmap->fb_pitch = new_pitch;
83    }
84    else {
85	paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
86	if (paddedWidth / 4 > 32767 || h > 32767)
87	    return NullPixmap;
88
89	exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
90
91	if (paddedWidth < pExaPixmap->fb_pitch)
92	    paddedWidth = pExaPixmap->fb_pitch;
93	datasize = h * paddedWidth;
94	pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0);
95    }
96
97    if (!pExaPixmap->driverPriv) {
98	swap(pExaScr, pScreen, DestroyPixmap);
99	pScreen->DestroyPixmap (pPixmap);
100	swap(pExaScr, pScreen, DestroyPixmap);
101	return NULL;
102    }
103
104    /* Allow ModifyPixmapHeader to set sys_ptr appropriately. */
105    pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
106    pExaPixmap->fb_ptr = NULL;
107    pExaPixmap->pDamage = NULL;
108    pExaPixmap->sys_ptr = NULL;
109
110    (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
111				    paddedWidth, NULL);
112
113    pExaPixmap->area = NULL;
114
115    exaSetAccelBlock(pExaScr, pExaPixmap,
116                     w, h, bpp);
117
118    pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
119
120    /* During a fallback we must prepare access. */
121    if (pExaScr->fallback_counter)
122	exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
123
124    return pPixmap;
125}
126
127Bool
128exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height, int depth,
129		      int bitsPerPixel, int devKind, pointer pPixData)
130{
131    ScreenPtr pScreen;
132    ExaScreenPrivPtr pExaScr;
133    ExaPixmapPrivPtr pExaPixmap;
134    Bool ret;
135
136    if (!pPixmap)
137        return FALSE;
138
139    pScreen = pPixmap->drawable.pScreen;
140    pExaScr = ExaGetScreenPriv(pScreen);
141    pExaPixmap = ExaGetPixmapPriv(pPixmap);
142
143    if (pExaPixmap) {
144        if (pPixData)
145            pExaPixmap->sys_ptr = pPixData;
146
147        if (devKind > 0)
148            pExaPixmap->sys_pitch = devKind;
149
150        if (width > 0 && height > 0 && bitsPerPixel > 0) {
151            exaSetFbPitch(pExaScr, pExaPixmap,
152                          width, height, bitsPerPixel);
153
154            exaSetAccelBlock(pExaScr, pExaPixmap,
155                             width, height, bitsPerPixel);
156        }
157    }
158
159    if (pExaScr->info->ModifyPixmapHeader) {
160	ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
161						bitsPerPixel, devKind, pPixData);
162	/* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
163	 * If pPixmap->devPrivate.ptr is non-NULL, then we've got a
164	 * !has_gpu_copy pixmap. We need to store the pointer,
165	 * because PrepareAccess won't be called.
166	 */
167	if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
168	    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
169	    pExaPixmap->sys_pitch = pPixmap->devKind;
170	}
171	if (ret == TRUE)
172	    goto out;
173    }
174
175    swap(pExaScr, pScreen, ModifyPixmapHeader);
176    ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
177					    bitsPerPixel, devKind, pPixData);
178    swap(pExaScr, pScreen, ModifyPixmapHeader);
179
180out:
181    /* Always NULL this, we don't want lingering pointers. */
182    pPixmap->devPrivate.ptr = NULL;
183
184    return ret;
185}
186
187Bool
188exaDestroyPixmap_driver (PixmapPtr pPixmap)
189{
190    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
191    ExaScreenPriv(pScreen);
192    Bool ret;
193
194    if (pPixmap->refcnt == 1)
195    {
196	ExaPixmapPriv (pPixmap);
197
198	exaDestroyPixmap(pPixmap);
199
200	if (pExaPixmap->driverPriv)
201	    pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
202	pExaPixmap->driverPriv = NULL;
203    }
204
205    swap(pExaScr, pScreen, DestroyPixmap);
206    ret = pScreen->DestroyPixmap (pPixmap);
207    swap(pExaScr, pScreen, DestroyPixmap);
208
209    return ret;
210}
211
212Bool
213exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap)
214{
215    ScreenPtr pScreen = pPixmap->drawable.pScreen;
216    ExaScreenPriv(pScreen);
217    pointer saved_ptr;
218    Bool ret;
219
220    saved_ptr = pPixmap->devPrivate.ptr;
221    pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
222    ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
223    pPixmap->devPrivate.ptr = saved_ptr;
224
225    return ret;
226}
227