1 /*
2
3 Copyright 1993, 1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26
27 */
28
29 #ifdef HAVE_DIX_CONFIG_H
30 #include <dix-config.h>
31 #endif
32
33 #include <X11/X.h>
34 #include "scrnintstr.h"
35 #include "mi.h"
36 #include "misc.h"
37 #include "os.h"
38 #include "windowstr.h"
39 #include "resource.h"
40 #include "dixstruct.h"
41 #include "gcstruct.h"
42 #include "servermd.h"
43 #include "site.h"
44 #include "X11/extensions/render.h"
45 #include "picturestr.h"
46 #include "randrstr.h"
47 /*
48 * Scratch pixmap management and device independent pixmap allocation
49 * function.
50 */
51
52 /* callable by ddx */
53 PixmapPtr
GetScratchPixmapHeader(ScreenPtr pScreen,int width,int height,int depth,int bitsPerPixel,int devKind,void * pPixData)54 GetScratchPixmapHeader(ScreenPtr pScreen, int width, int height, int depth,
55 int bitsPerPixel, int devKind, void *pPixData)
56 {
57 PixmapPtr pPixmap = pScreen->pScratchPixmap;
58
59 if (pPixmap)
60 pScreen->pScratchPixmap = NULL;
61 else
62 /* width and height of 0 means don't allocate any pixmap data */
63 pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0);
64
65 if (pPixmap) {
66 if ((*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth,
67 bitsPerPixel, devKind, pPixData))
68 return pPixmap;
69 (*pScreen->DestroyPixmap) (pPixmap);
70 }
71 return NullPixmap;
72 }
73
74 /* callable by ddx */
75 void
FreeScratchPixmapHeader(PixmapPtr pPixmap)76 FreeScratchPixmapHeader(PixmapPtr pPixmap)
77 {
78 if (pPixmap) {
79 ScreenPtr pScreen = pPixmap->drawable.pScreen;
80
81 pPixmap->devPrivate.ptr = NULL; /* lest ddx chases bad ptr */
82 if (pScreen->pScratchPixmap)
83 (*pScreen->DestroyPixmap) (pPixmap);
84 else
85 pScreen->pScratchPixmap = pPixmap;
86 }
87 }
88
89 Bool
CreateScratchPixmapsForScreen(ScreenPtr pScreen)90 CreateScratchPixmapsForScreen(ScreenPtr pScreen)
91 {
92 unsigned int pixmap_size;
93
94 pixmap_size = sizeof(PixmapRec) + dixScreenSpecificPrivatesSize(pScreen, PRIVATE_PIXMAP);
95 pScreen->totalPixmapSize =
96 BitmapBytePad(pixmap_size * 8);
97
98 /* let it be created on first use */
99 pScreen->pScratchPixmap = NULL;
100 return TRUE;
101 }
102
103 void
FreeScratchPixmapsForScreen(ScreenPtr pScreen)104 FreeScratchPixmapsForScreen(ScreenPtr pScreen)
105 {
106 FreeScratchPixmapHeader(pScreen->pScratchPixmap);
107 }
108
109 /* callable by ddx */
110 PixmapPtr
AllocatePixmap(ScreenPtr pScreen,int pixDataSize)111 AllocatePixmap(ScreenPtr pScreen, int pixDataSize)
112 {
113 PixmapPtr pPixmap;
114
115 assert(pScreen->totalPixmapSize > 0);
116
117 if (pScreen->totalPixmapSize > ((size_t) - 1) - pixDataSize)
118 return NullPixmap;
119
120 pPixmap = calloc(1, pScreen->totalPixmapSize + pixDataSize);
121 if (!pPixmap)
122 return NullPixmap;
123
124 dixInitScreenPrivates(pScreen, pPixmap, pPixmap + 1, PRIVATE_PIXMAP);
125 return pPixmap;
126 }
127
128 /* callable by ddx */
129 void
FreePixmap(PixmapPtr pPixmap)130 FreePixmap(PixmapPtr pPixmap)
131 {
132 dixFiniPrivates(pPixmap, PRIVATE_PIXMAP);
133 free(pPixmap);
134 }
135
PixmapUnshareSlavePixmap(PixmapPtr slave_pixmap)136 void PixmapUnshareSlavePixmap(PixmapPtr slave_pixmap)
137 {
138 int ihandle = -1;
139 ScreenPtr pScreen = slave_pixmap->drawable.pScreen;
140 pScreen->SetSharedPixmapBacking(slave_pixmap, ((void *)(long)ihandle));
141 }
142
PixmapShareToSlave(PixmapPtr pixmap,ScreenPtr slave)143 PixmapPtr PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave)
144 {
145 PixmapPtr spix;
146 int ret;
147 void *handle;
148 ScreenPtr master = pixmap->drawable.pScreen;
149 int depth = pixmap->drawable.depth;
150
151 ret = master->SharePixmapBacking(pixmap, slave, &handle);
152 if (ret == FALSE)
153 return NULL;
154
155 spix = slave->CreatePixmap(slave, 0, 0, depth,
156 CREATE_PIXMAP_USAGE_SHARED);
157 slave->ModifyPixmapHeader(spix, pixmap->drawable.width,
158 pixmap->drawable.height, depth, 0,
159 pixmap->devKind, NULL);
160
161 /* have the slave pixmap take a reference on the master pixmap
162 later we destroy them both at the same time */
163 pixmap->refcnt++;
164
165 spix->master_pixmap = pixmap;
166
167 ret = slave->SetSharedPixmapBacking(spix, handle);
168 if (ret == FALSE) {
169 slave->DestroyPixmap(spix);
170 return NULL;
171 }
172
173 return spix;
174 }
175
176 static void
PixmapDirtyDamageDestroy(DamagePtr damage,void * closure)177 PixmapDirtyDamageDestroy(DamagePtr damage, void *closure)
178 {
179 PixmapDirtyUpdatePtr dirty = closure;
180
181 dirty->damage = NULL;
182 }
183
184 Bool
PixmapStartDirtyTracking(DrawablePtr src,PixmapPtr slave_dst,int x,int y,int dst_x,int dst_y,Rotation rotation)185 PixmapStartDirtyTracking(DrawablePtr src,
186 PixmapPtr slave_dst,
187 int x, int y, int dst_x, int dst_y,
188 Rotation rotation)
189 {
190 ScreenPtr screen = src->pScreen;
191 PixmapDirtyUpdatePtr dirty_update;
192 RegionPtr damageregion;
193 RegionRec dstregion;
194 BoxRec box;
195
196 dirty_update = calloc(1, sizeof(PixmapDirtyUpdateRec));
197 if (!dirty_update)
198 return FALSE;
199
200 dirty_update->src = src;
201 dirty_update->slave_dst = slave_dst;
202 dirty_update->x = x;
203 dirty_update->y = y;
204 dirty_update->dst_x = dst_x;
205 dirty_update->dst_y = dst_y;
206 dirty_update->rotation = rotation;
207 dirty_update->damage = DamageCreate(NULL, PixmapDirtyDamageDestroy,
208 DamageReportNone, TRUE, screen,
209 dirty_update);
210
211 if (rotation != RR_Rotate_0) {
212 RRTransformCompute(x, y,
213 slave_dst->drawable.width,
214 slave_dst->drawable.height,
215 rotation,
216 NULL,
217 &dirty_update->transform,
218 &dirty_update->f_transform,
219 &dirty_update->f_inverse);
220 }
221 if (!dirty_update->damage) {
222 free(dirty_update);
223 return FALSE;
224 }
225
226 /* Damage destination rectangle so that the destination pixmap contents
227 * will get fully initialized
228 */
229 box.x1 = dirty_update->x;
230 box.y1 = dirty_update->y;
231 if (dirty_update->rotation == RR_Rotate_90 ||
232 dirty_update->rotation == RR_Rotate_270) {
233 box.x2 = dirty_update->x + slave_dst->drawable.height;
234 box.y2 = dirty_update->y + slave_dst->drawable.width;
235 } else {
236 box.x2 = dirty_update->x + slave_dst->drawable.width;
237 box.y2 = dirty_update->y + slave_dst->drawable.height;
238 }
239 RegionInit(&dstregion, &box, 1);
240 damageregion = DamageRegion(dirty_update->damage);
241 RegionUnion(damageregion, damageregion, &dstregion);
242 RegionUninit(&dstregion);
243
244 DamageRegister(src, dirty_update->damage);
245 xorg_list_add(&dirty_update->ent, &screen->pixmap_dirty_list);
246 return TRUE;
247 }
248
249 Bool
PixmapStopDirtyTracking(DrawablePtr src,PixmapPtr slave_dst)250 PixmapStopDirtyTracking(DrawablePtr src, PixmapPtr slave_dst)
251 {
252 ScreenPtr screen = src->pScreen;
253 PixmapDirtyUpdatePtr ent, safe;
254
255 xorg_list_for_each_entry_safe(ent, safe, &screen->pixmap_dirty_list, ent) {
256 if (ent->src == src && ent->slave_dst == slave_dst) {
257 if (ent->damage)
258 DamageDestroy(ent->damage);
259 xorg_list_del(&ent->ent);
260 free(ent);
261 }
262 }
263 return TRUE;
264 }
265
266 static void
PixmapDirtyCopyArea(PixmapPtr dst,PixmapDirtyUpdatePtr dirty,RegionPtr dirty_region)267 PixmapDirtyCopyArea(PixmapPtr dst,
268 PixmapDirtyUpdatePtr dirty,
269 RegionPtr dirty_region)
270 {
271 DrawablePtr src = dirty->src;
272 ScreenPtr pScreen = src->pScreen;
273 int n;
274 BoxPtr b;
275 GCPtr pGC;
276
277 n = RegionNumRects(dirty_region);
278 b = RegionRects(dirty_region);
279
280 pGC = GetScratchGC(src->depth, pScreen);
281 if (pScreen->root) {
282 ChangeGCVal subWindowMode;
283
284 subWindowMode.val = IncludeInferiors;
285 ChangeGC(NullClient, pGC, GCSubwindowMode, &subWindowMode);
286 }
287 ValidateGC(&dst->drawable, pGC);
288
289 while (n--) {
290 BoxRec dst_box;
291 int w, h;
292
293 dst_box = *b;
294 w = dst_box.x2 - dst_box.x1;
295 h = dst_box.y2 - dst_box.y1;
296
297 pGC->ops->CopyArea(src, &dst->drawable, pGC,
298 dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h,
299 dirty->dst_x + dst_box.x1,
300 dirty->dst_y + dst_box.y1);
301 b++;
302 }
303 FreeScratchGC(pGC);
304 }
305
306 static void
PixmapDirtyCompositeRotate(PixmapPtr dst_pixmap,PixmapDirtyUpdatePtr dirty,RegionPtr dirty_region)307 PixmapDirtyCompositeRotate(PixmapPtr dst_pixmap,
308 PixmapDirtyUpdatePtr dirty,
309 RegionPtr dirty_region)
310 {
311 ScreenPtr pScreen = dirty->src->pScreen;
312 PictFormatPtr format = PictureWindowFormat(pScreen->root);
313 PicturePtr src, dst;
314 XID include_inferiors = IncludeInferiors;
315 int n = RegionNumRects(dirty_region);
316 BoxPtr b = RegionRects(dirty_region);
317 int error;
318
319 src = CreatePicture(None,
320 dirty->src,
321 format,
322 CPSubwindowMode,
323 &include_inferiors, serverClient, &error);
324 if (!src)
325 return;
326
327 dst = CreatePicture(None,
328 &dst_pixmap->drawable,
329 format, 0L, NULL, serverClient, &error);
330 if (!dst)
331 return;
332
333 error = SetPictureTransform(src, &dirty->transform);
334 if (error)
335 return;
336 while (n--) {
337 BoxRec dst_box;
338
339 dst_box = *b;
340 dst_box.x1 += dirty->x;
341 dst_box.x2 += dirty->x;
342 dst_box.y1 += dirty->y;
343 dst_box.y2 += dirty->y;
344 pixman_f_transform_bounds(&dirty->f_inverse, &dst_box);
345
346 CompositePicture(PictOpSrc,
347 src, NULL, dst,
348 dst_box.x1,
349 dst_box.y1,
350 0, 0,
351 dst_box.x1,
352 dst_box.y1,
353 dst_box.x2 - dst_box.x1,
354 dst_box.y2 - dst_box.y1);
355 b++;
356 }
357
358 FreePicture(src, None);
359 FreePicture(dst, None);
360 }
361
362 /*
363 * this function can possibly be improved and optimised, by clipping
364 * instead of iterating
365 * Drivers are free to implement their own version of this.
366 */
PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty)367 Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty)
368 {
369 ScreenPtr pScreen = dirty->src->pScreen;
370 RegionPtr region = DamageRegion(dirty->damage);
371 PixmapPtr dst;
372 SourceValidateProcPtr SourceValidate;
373 RegionRec pixregion;
374 BoxRec box;
375
376 dst = dirty->slave_dst->master_pixmap;
377 if (!dst)
378 dst = dirty->slave_dst;
379
380 box.x1 = 0;
381 box.y1 = 0;
382 if (dirty->rotation == RR_Rotate_90 ||
383 dirty->rotation == RR_Rotate_270) {
384 box.x2 = dst->drawable.height;
385 box.y2 = dst->drawable.width;
386 } else {
387 box.x2 = dst->drawable.width;
388 box.y2 = dst->drawable.height;
389 }
390 RegionInit(&pixregion, &box, 1);
391
392 /*
393 * SourceValidate is used by the software cursor code
394 * to pull the cursor off of the screen when reading
395 * bits from the frame buffer. Bypassing this function
396 * leaves the software cursor in place
397 */
398 SourceValidate = pScreen->SourceValidate;
399 pScreen->SourceValidate = miSourceValidate;
400
401 RegionTranslate(&pixregion, dirty->x, dirty->y);
402 RegionIntersect(&pixregion, &pixregion, region);
403
404 if (RegionNil(&pixregion)) {
405 RegionUninit(&pixregion);
406 return FALSE;
407 }
408
409 RegionTranslate(&pixregion, -dirty->x, -dirty->y);
410
411 if (!pScreen->root || dirty->rotation == RR_Rotate_0)
412 PixmapDirtyCopyArea(dst, dirty, &pixregion);
413 else
414 PixmapDirtyCompositeRotate(dst, dirty, &pixregion);
415 pScreen->SourceValidate = SourceValidate;
416 return TRUE;
417 }
418