1 /*****************************************************************************
2  * driDrawable.c: Lean Version of DRI utilities.
3  *
4  * Copyright (c) 2005 Thomas Hellstrom. All rights reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <X11/Xlibint.h>
26 #include <X11/Xutil.h>
27 #include "xf86drm.h"
28 #include "drm.h"
29 #include "xf86dri.h"
30 #include "drm_sarea.h"
31 #include "driDrawable.h"
32 
33 static unsigned
drawStamp(volatile drm_sarea_t * pSarea,int index)34 drawStamp(volatile drm_sarea_t * pSarea, int index)
35 {
36     return pSarea->drawableTable[index].stamp;
37 }
38 
39 int
getDRIDrawableInfoLocked(void * drawHash,Display * display,int screen,Drawable draw,unsigned lockFlags,int drmFD,drm_context_t drmContext,drmAddress sarea,Bool updateInfo,drawableInfo ** info,unsigned long infoSize)40 getDRIDrawableInfoLocked(void *drawHash, Display * display, int screen,
41     Drawable draw, unsigned lockFlags, int drmFD, drm_context_t drmContext,
42     drmAddress sarea, Bool updateInfo, drawableInfo ** info,
43     unsigned long infoSize)
44 {
45     drawableInfo *drawInfo;
46     void *res;
47     drm_drawable_t drmDraw = 0;
48     volatile drm_sarea_t *pSarea = (drm_sarea_t *) sarea;
49     drm_clip_rect_t *clipFront, *clipBack;
50 
51     int ret;
52 
53     if (drmHashLookup(drawHash, (unsigned long)draw, &res)) {
54 
55 	/*
56 	 * The drawable is unknown to us. Create it and put it in the
57 	 * hash table.
58 	 */
59 
60 	DRM_UNLOCK(drmFD, &pSarea->lock, drmContext);
61 	if (!uniDRICreateDrawable(display, screen, draw, &drmDraw)) {
62 	    DRM_LOCK(drmFD, &pSarea->lock, drmContext, lockFlags);
63 	    return 1;
64 	}
65 	DRM_LOCK(drmFD, &pSarea->lock, drmContext, lockFlags);
66 
67 	drawInfo = (drawableInfo *) malloc(infoSize);
68 	if (!drawInfo)
69 	    return 1;
70 
71 	drawInfo->drmDraw = drmDraw;
72 	drawInfo->stamp = 0;
73 	drawInfo->clipFront = 0;
74 	drawInfo->clipBack = 0;
75 
76 	drmHashInsert(drawHash, (unsigned long)draw, drawInfo);
77 
78     } else {
79 	drawInfo = res;
80     }
81 
82     drawInfo->touched = FALSE;
83     while (!drawInfo->clipFront
84 	|| drawInfo->stamp != drawStamp(pSarea, drawInfo->index)) {
85 
86 	/*
87 	 * The drawable has been touched since we last got info about it.
88 	 * obtain new info from the X server.
89 	 */
90 
91 	drawInfo->touched = TRUE;
92 
93 	if (updateInfo || !drawInfo->clipFront) {
94 	    DRM_UNLOCK(drmFD, &pSarea->lock, drmContext);
95 
96 	    ret = uniDRIGetDrawableInfo(display, screen, draw,
97 		&drawInfo->index, &drawInfo->stamp, &drawInfo->x,
98 		&drawInfo->y, &drawInfo->w, &drawInfo->h,
99 		&drawInfo->numClipFront, &clipFront,
100 		&drawInfo->backX, &drawInfo->backY,
101 		&drawInfo->numClipBack, &clipBack);
102 
103 	    DRM_LIGHT_LOCK(drmFD, &pSarea->lock, drmContext);
104 
105 	    /*
106 	     * Error. Probably the drawable is destroyed. Return error and old values.
107 	     */
108 
109 	    if (!ret) {
110 		free(drawInfo);
111 		drawInfo = NULL;
112 		drmHashDelete(drawHash, (unsigned long)draw);
113 
114 		DRM_UNLOCK(drmFD, &pSarea->lock, drmContext);
115 		uniDRIDestroyDrawable(display, screen, draw);
116 		DRM_LOCK(drmFD, &pSarea->lock, drmContext, lockFlags);
117 
118 		return 1;
119 	    }
120 
121 	    if (drawInfo->stamp != drawStamp(pSarea, drawInfo->index)) {
122 
123 		/*
124 		 * The info is already outdated. Sigh. Have another go.
125 		 */
126 
127 		XFree(clipFront);
128 		XFree(clipBack);
129 		continue;
130 	    }
131 
132 	    if (drawInfo->clipFront)
133 		XFree(drawInfo->clipFront);
134 	    drawInfo->clipFront = clipFront;
135 	    if (drawInfo->clipBack)
136 		XFree(drawInfo->clipBack);
137 	    drawInfo->clipBack = clipBack;
138 	} else {
139 	    if (!drawInfo->clipFront)
140 		drawInfo->clipFront = (drm_clip_rect_t *) ~ 0UL;
141 	    drawInfo->stamp = drawStamp(pSarea, drawInfo->index);
142 	}
143     }
144     *info = drawInfo;
145     return 0;
146 }
147 
148 void
driDestroyHashContents(void * drawHash)149 driDestroyHashContents(void *drawHash)
150 {
151     unsigned long key;
152     void *content;
153     drawableInfo *drawInfo;
154 
155     if (drmHashFirst(drawHash, &key, &content) < 1)
156 	return;
157     drawInfo = (drawableInfo *) content;
158     if (drawInfo->clipBack)
159 	XFree(drawInfo->clipBack);
160     if (drawInfo->clipFront)
161 	XFree(drawInfo->clipFront);
162     free(drawInfo);
163     while (drmHashNext(drawHash, &key, &content) == 1) {
164 	drawInfo = (drawableInfo *) content;
165 	if (drawInfo->clipBack)
166 	    XFree(drawInfo->clipBack);
167 	if (drawInfo->clipFront)
168 	    XFree(drawInfo->clipFront);
169 	free(drawInfo);
170     }
171 
172     return;
173 }
174