1 /*
2 * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <assert.h>
28 #include <sys/stat.h>
29
30 #include <xf86drm.h>
31
32 #include <X11/Xlibint.h>
33 #include <X11/Xlib.h>
34 #include "va.h"
35 #include "va_backend.h"
36
37 #include "va_dri2.h"
38 #include "va_dri2tokens.h"
39 #include "va_dricommon.h"
40
41 #define __DRI_BUFFER_FRONT_LEFT 0
42 #define __DRI_BUFFER_BACK_LEFT 1
43 #define __DRI_BUFFER_FRONT_RIGHT 2
44 #define __DRI_BUFFER_BACK_RIGHT 3
45 #define __DRI_BUFFER_DEPTH 4
46 #define __DRI_BUFFER_STENCIL 5
47 #define __DRI_BUFFER_ACCUM 6
48 #define __DRI_BUFFER_FAKE_FRONT_LEFT 7
49 #define __DRI_BUFFER_FAKE_FRONT_RIGHT 8
50
51 struct dri2_drawable {
52 struct dri_drawable base;
53 union dri_buffer buffers[5];
54 int width;
55 int height;
56 int has_backbuffer;
57 int back_index;
58 int front_index;
59 };
60
61 static int gsDRI2SwapAvailable;
62
63 static struct dri_drawable *
dri2CreateDrawable(VADriverContextP ctx,XID x_drawable)64 dri2CreateDrawable(VADriverContextP ctx, XID x_drawable)
65 {
66 struct dri2_drawable *dri2_drawable;
67
68 dri2_drawable = calloc(1, sizeof(*dri2_drawable));
69
70 if (!dri2_drawable)
71 return NULL;
72
73 dri2_drawable->base.x_drawable = x_drawable;
74 dri2_drawable->base.x = 0;
75 dri2_drawable->base.y = 0;
76 VA_DRI2CreateDrawable(ctx->native_dpy, x_drawable);
77
78 return &dri2_drawable->base;
79 }
80
81 static void
dri2DestroyDrawable(VADriverContextP ctx,struct dri_drawable * dri_drawable)82 dri2DestroyDrawable(VADriverContextP ctx, struct dri_drawable *dri_drawable)
83 {
84 VA_DRI2DestroyDrawable(ctx->native_dpy, dri_drawable->x_drawable);
85 free(dri_drawable);
86 }
87
88 static void
dri2SwapBuffer(VADriverContextP ctx,struct dri_drawable * dri_drawable)89 dri2SwapBuffer(VADriverContextP ctx, struct dri_drawable *dri_drawable)
90 {
91 struct dri2_drawable *dri2_drawable = (struct dri2_drawable *)dri_drawable;
92 XRectangle xrect;
93 XserverRegion region;
94
95 if (dri2_drawable->has_backbuffer) {
96 if (gsDRI2SwapAvailable) {
97 CARD64 ret;
98 VA_DRI2SwapBuffers(ctx->native_dpy, dri_drawable->x_drawable,
99 0, 1, 0,
100 &ret);
101 } else {
102 xrect.x = 0;
103 xrect.y = 0;
104 xrect.width = dri2_drawable->width;
105 xrect.height = dri2_drawable->height;
106
107 region = XFixesCreateRegion(ctx->native_dpy, &xrect, 1);
108 VA_DRI2CopyRegion(ctx->native_dpy, dri_drawable->x_drawable, region,
109 DRI2BufferFrontLeft, DRI2BufferBackLeft);
110 XFixesDestroyRegion(ctx->native_dpy, region);
111 }
112 }
113 }
114
115 static union dri_buffer *
dri2GetRenderingBuffer(VADriverContextP ctx,struct dri_drawable * dri_drawable)116 dri2GetRenderingBuffer(VADriverContextP ctx, struct dri_drawable *dri_drawable)
117 {
118 struct dri2_drawable *dri2_drawable = (struct dri2_drawable *)dri_drawable;
119 int i;
120 int count;
121 unsigned int attachments[5];
122 VA_DRI2Buffer *buffers;
123
124 i = 0;
125 if (dri_drawable->is_window)
126 attachments[i++] = __DRI_BUFFER_BACK_LEFT;
127 else
128 attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
129
130 buffers = VA_DRI2GetBuffers(ctx->native_dpy, dri_drawable->x_drawable,
131 &dri2_drawable->width, &dri2_drawable->height,
132 attachments, i, &count);
133 if (buffers == NULL)
134 return NULL;
135
136 dri2_drawable->has_backbuffer = 0;
137
138 for (i = 0; i < count; i++) {
139 dri2_drawable->buffers[i].dri2.attachment = buffers[i].attachment;
140 dri2_drawable->buffers[i].dri2.name = buffers[i].name;
141 dri2_drawable->buffers[i].dri2.pitch = buffers[i].pitch;
142 dri2_drawable->buffers[i].dri2.cpp = buffers[i].cpp;
143 dri2_drawable->buffers[i].dri2.flags = buffers[i].flags;
144
145 if (buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) {
146 dri2_drawable->has_backbuffer = 1;
147 dri2_drawable->back_index = i;
148 }
149
150 if (buffers[i].attachment == __DRI_BUFFER_FRONT_LEFT)
151 dri2_drawable->front_index = i;
152 }
153
154 dri_drawable->width = dri2_drawable->width;
155 dri_drawable->height = dri2_drawable->height;
156 Xfree(buffers);
157
158 if (dri2_drawable->has_backbuffer)
159 return &dri2_drawable->buffers[dri2_drawable->back_index];
160
161 return &dri2_drawable->buffers[dri2_drawable->front_index];
162 }
163
164 static void
dri2Close(VADriverContextP ctx)165 dri2Close(VADriverContextP ctx)
166 {
167 struct dri_state *dri_state = (struct dri_state *)ctx->drm_state;
168
169 va_dri_free_drawable_hashtable(ctx);
170
171 if (dri_state->base.fd >= 0)
172 close(dri_state->base.fd);
173 }
174
175 int
va_isRenderNodeFd(int fd)176 va_isRenderNodeFd(int fd)
177 {
178 struct stat st;
179 char *name;
180
181 /* Check by device node */
182 if (fstat(fd, &st) == 0)
183 return S_ISCHR(st.st_mode) && (st.st_rdev & 0x80);
184
185 /* Check by device name */
186 name = drmGetDeviceNameFromFd(fd);
187 if (name) {
188 /* drmGetDeviceNameFromFd returns a strdup'ed string */
189 int r = (strncmp(name, "/dev/dri/renderD", 16) == 0);
190 drmFree(name);
191 return r;
192 }
193
194 /* Unrecoverable error */
195 return -1;
196 }
197
198 Bool
va_isDRI2Connected(VADriverContextP ctx,char ** driver_name)199 va_isDRI2Connected(VADriverContextP ctx, char **driver_name)
200 {
201 struct dri_state *dri_state = (struct dri_state *)ctx->drm_state;
202 int major, minor;
203 int error_base;
204 int event_base;
205 char *device_name = NULL;
206 int is_render_nodes;
207 drm_magic_t magic;
208 *driver_name = NULL;
209
210 if (!VA_DRI2QueryExtension(ctx->native_dpy, &event_base, &error_base))
211 goto err_out;
212
213 if (!VA_DRI2QueryVersion(ctx->native_dpy, &major, &minor))
214 goto err_out;
215
216
217 if (!VA_DRI2Connect(ctx->native_dpy, RootWindow(ctx->native_dpy, ctx->x11_screen),
218 driver_name, &device_name))
219 goto err_out;
220
221 if ((dri_state->base.fd != -1) && (dri_state->base.auth_type != VA_NONE))
222 goto success_out;
223
224 dri_state->base.fd = open(device_name, O_RDWR);
225
226 if (dri_state->base.fd < 0 || (is_render_nodes = va_isRenderNodeFd(dri_state->base.fd)) < 0)
227 goto err_out;
228
229 if (!is_render_nodes) {
230 if (drmGetMagic(dri_state->base.fd, &magic))
231 goto err_out;
232
233 if (!VA_DRI2Authenticate(ctx->native_dpy, RootWindow(ctx->native_dpy, ctx->x11_screen),
234 magic))
235 goto err_out;
236 }
237 dri_state->base.auth_type = VA_DRI2;
238 dri_state->createDrawable = dri2CreateDrawable;
239 dri_state->destroyDrawable = dri2DestroyDrawable;
240 dri_state->swapBuffer = dri2SwapBuffer;
241 dri_state->getRenderingBuffer = dri2GetRenderingBuffer;
242 dri_state->close = dri2Close;
243 gsDRI2SwapAvailable = (minor >= 2);
244
245 success_out:
246 Xfree(device_name);
247
248 return True;
249
250 err_out:
251 if (device_name)
252 Xfree(device_name);
253
254 if (*driver_name)
255 Xfree(*driver_name);
256
257 if (dri_state->base.fd >= 0)
258 close(dri_state->base.fd);
259
260 *driver_name = NULL;
261 dri_state->base.fd = -1;
262
263 return False;
264 }
265
266