exa_mixed.c revision 6747b715
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 + better initial placement code.
35 */
36
37static _X_INLINE void*
38ExaGetPixmapAddress(PixmapPtr p)
39{
40    ExaPixmapPriv(p);
41
42    return pExaPixmap->sys_ptr;
43}
44
45/**
46 * exaCreatePixmap() creates a new pixmap.
47 */
48PixmapPtr
49exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
50		unsigned usage_hint)
51{
52    PixmapPtr pPixmap;
53    ExaPixmapPrivPtr	pExaPixmap;
54    int bpp;
55    size_t paddedWidth;
56    ExaScreenPriv(pScreen);
57
58    if (w > 32767 || h > 32767)
59	return NullPixmap;
60
61    swap(pExaScr, pScreen, CreatePixmap);
62    pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
63    swap(pExaScr, pScreen, CreatePixmap);
64
65    if (!pPixmap)
66        return NULL;
67
68    pExaPixmap = ExaGetPixmapPriv(pPixmap);
69    pExaPixmap->driverPriv = NULL;
70
71    bpp = pPixmap->drawable.bitsPerPixel;
72
73    paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
74    if (paddedWidth / 4 > 32767 || h > 32767)
75        return NullPixmap;
76
77    /* We will allocate the system pixmap later if needed. */
78    pPixmap->devPrivate.ptr = NULL;
79    pExaPixmap->sys_ptr = NULL;
80    pExaPixmap->sys_pitch = paddedWidth;
81
82    pExaPixmap->area = NULL;
83    pExaPixmap->fb_ptr = NULL;
84    pExaPixmap->pDamage = NULL;
85
86    exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
87    exaSetAccelBlock(pExaScr, pExaPixmap,
88	w, h, bpp);
89
90    (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
91				    paddedWidth, NULL);
92
93    /* A scratch pixmap will become a driver pixmap right away. */
94    if (!w || !h) {
95	exaCreateDriverPixmap_mixed(pPixmap);
96	pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
97    } else {
98	pExaPixmap->use_gpu_copy = FALSE;
99
100	if (w == 1 && h == 1) {
101	    pExaPixmap->sys_ptr = malloc((pPixmap->drawable.bitsPerPixel + 7) / 8);
102
103	    /* Set up damage tracking */
104	    pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
105					       DamageReportNonEmpty, TRUE,
106					       pPixmap->drawable.pScreen,
107					       pPixmap);
108
109	    DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
110	    /* This ensures that pending damage reflects the current operation. */
111	    /* This is used by exa to optimize migration. */
112	    DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
113	}
114    }
115
116    /* During a fallback we must prepare access. */
117    if (pExaScr->fallback_counter)
118	exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
119
120    return pPixmap;
121}
122
123Bool
124exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
125		      int bitsPerPixel, int devKind, pointer pPixData)
126{
127    ScreenPtr pScreen;
128    ExaScreenPrivPtr pExaScr;
129    ExaPixmapPrivPtr pExaPixmap;
130    Bool ret, has_gpu_copy;
131
132    if (!pPixmap)
133        return FALSE;
134
135    pScreen = pPixmap->drawable.pScreen;
136    pExaScr = ExaGetScreenPriv(pScreen);
137    pExaPixmap = ExaGetPixmapPriv(pPixmap);
138
139    if (pPixData) {
140	if (pExaPixmap->driverPriv) {
141	    if (pExaPixmap->pDamage) {
142		DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
143		DamageDestroy(pExaPixmap->pDamage);
144		pExaPixmap->pDamage = NULL;
145	    }
146
147	    pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
148	    pExaPixmap->driverPriv = NULL;
149	}
150
151	pExaPixmap->use_gpu_copy = FALSE;
152	pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
153    }
154
155    has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
156
157    if (width <= 0)
158	width = pPixmap->drawable.width;
159
160    if (height <= 0)
161	height = pPixmap->drawable.height;
162
163    if (bitsPerPixel <= 0) {
164	if (depth <= 0)
165	    bitsPerPixel = pPixmap->drawable.bitsPerPixel;
166	else
167	    bitsPerPixel = BitsPerPixel(depth);
168    }
169
170    if (depth <= 0)
171	depth = pPixmap->drawable.depth;
172
173    if (width != pPixmap->drawable.width ||
174	height != pPixmap->drawable.height ||
175	depth != pPixmap->drawable.depth ||
176	bitsPerPixel != pPixmap->drawable.bitsPerPixel) {
177	if (pExaPixmap->driverPriv) {
178            exaSetFbPitch(pExaScr, pExaPixmap,
179                          width, height, bitsPerPixel);
180
181            exaSetAccelBlock(pExaScr, pExaPixmap,
182                             width, height, bitsPerPixel);
183            RegionEmpty(&pExaPixmap->validFB);
184        }
185
186	/* Need to re-create system copy if there's also a GPU copy */
187	if (has_gpu_copy && pExaPixmap->sys_ptr) {
188	    free(pExaPixmap->sys_ptr);
189	    pExaPixmap->sys_ptr = NULL;
190	    pExaPixmap->sys_pitch = devKind > 0 ? devKind :
191	        PixmapBytePad(width, depth);
192	    DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
193	    DamageDestroy(pExaPixmap->pDamage);
194	    pExaPixmap->pDamage = NULL;
195	    RegionEmpty(&pExaPixmap->validSys);
196
197	    if (pExaScr->deferred_mixed_pixmap == pPixmap)
198		pExaScr->deferred_mixed_pixmap = NULL;
199	}
200    }
201
202    if (has_gpu_copy) {
203	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
204	pPixmap->devKind = pExaPixmap->fb_pitch;
205    } else {
206	pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
207	pPixmap->devKind = pExaPixmap->sys_pitch;
208    }
209
210    /* Only pass driver pixmaps to the driver. */
211    if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) {
212	ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
213						bitsPerPixel, devKind, pPixData);
214	if (ret == TRUE)
215	    goto out;
216    }
217
218    swap(pExaScr, pScreen, ModifyPixmapHeader);
219    ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
220					    bitsPerPixel, devKind, pPixData);
221    swap(pExaScr, pScreen, ModifyPixmapHeader);
222
223out:
224    if (has_gpu_copy) {
225	pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr;
226	pExaPixmap->fb_pitch = pPixmap->devKind;
227    } else {
228	pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
229	pExaPixmap->sys_pitch = pPixmap->devKind;
230    }
231    /* Always NULL this, we don't want lingering pointers. */
232    pPixmap->devPrivate.ptr = NULL;
233
234    return ret;
235}
236
237Bool
238exaDestroyPixmap_mixed(PixmapPtr pPixmap)
239{
240    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
241    ExaScreenPriv(pScreen);
242    Bool ret;
243
244    if (pPixmap->refcnt == 1)
245    {
246	ExaPixmapPriv (pPixmap);
247
248	exaDestroyPixmap(pPixmap);
249
250	if (pExaScr->deferred_mixed_pixmap == pPixmap)
251	    pExaScr->deferred_mixed_pixmap = NULL;
252
253	if (pExaPixmap->driverPriv)
254	    pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
255	pExaPixmap->driverPriv = NULL;
256
257	if (pExaPixmap->pDamage) {
258	    free(pExaPixmap->sys_ptr);
259	    pExaPixmap->sys_ptr = NULL;
260	    pExaPixmap->pDamage = NULL;
261	}
262    }
263
264    swap(pExaScr, pScreen, DestroyPixmap);
265    ret = pScreen->DestroyPixmap (pPixmap);
266    swap(pExaScr, pScreen, DestroyPixmap);
267
268    return ret;
269}
270
271Bool
272exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap)
273{
274    ScreenPtr pScreen = pPixmap->drawable.pScreen;
275    ExaScreenPriv(pScreen);
276    ExaPixmapPriv(pPixmap);
277    pointer saved_ptr;
278    Bool ret;
279
280    if (!pExaPixmap->driverPriv)
281	return FALSE;
282
283    saved_ptr = pPixmap->devPrivate.ptr;
284    pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
285    ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
286    pPixmap->devPrivate.ptr = saved_ptr;
287
288    return ret;
289}
290