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 29 #include <xf86drm.h> 30 31 #include <X11/Xlibint.h> 32 #include <X11/Xlib.h> 33 #include "va.h" 34 #include "va_backend.h" 35 36 #include "va_dri2.h" 37 #include "va_dri2tokens.h" 38 #include "va_dricommon.h" 39 40 #define __DRI_BUFFER_FRONT_LEFT 0 41 #define __DRI_BUFFER_BACK_LEFT 1 42 #define __DRI_BUFFER_FRONT_RIGHT 2 43 #define __DRI_BUFFER_BACK_RIGHT 3 44 #define __DRI_BUFFER_DEPTH 4 45 #define __DRI_BUFFER_STENCIL 5 46 #define __DRI_BUFFER_ACCUM 6 47 #define __DRI_BUFFER_FAKE_FRONT_LEFT 7 48 #define __DRI_BUFFER_FAKE_FRONT_RIGHT 8 49 50 struct dri2_drawable 51 { 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 * 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 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 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, 0, 0, 99 0, &ret); 100 } else { 101 xrect.x = 0; 102 xrect.y = 0; 103 xrect.width = dri2_drawable->width; 104 xrect.height = dri2_drawable->height; 105 106 region = XFixesCreateRegion(ctx->native_dpy, &xrect, 1); 107 VA_DRI2CopyRegion(ctx->native_dpy, dri_drawable->x_drawable, region, 108 DRI2BufferFrontLeft, DRI2BufferBackLeft); 109 XFixesDestroyRegion(ctx->native_dpy, region); 110 } 111 } 112 } 113 114 static union dri_buffer * 115 dri2GetRenderingBuffer(VADriverContextP ctx, struct dri_drawable *dri_drawable) 116 { 117 struct dri2_drawable *dri2_drawable = (struct dri2_drawable *)dri_drawable; 118 int i; 119 int count; 120 unsigned int attachments[5]; 121 VA_DRI2Buffer *buffers; 122 123 i = 0; 124 if (dri_drawable->is_window) 125 attachments[i++] = __DRI_BUFFER_BACK_LEFT; 126 else 127 attachments[i++] = __DRI_BUFFER_FRONT_LEFT; 128 129 buffers = VA_DRI2GetBuffers(ctx->native_dpy, dri_drawable->x_drawable, 130 &dri2_drawable->width, &dri2_drawable->height, 131 attachments, i, &count); 132 assert(buffers); 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 void 165 dri2Close(VADriverContextP ctx) 166 { 167 struct dri_state *dri_state = (struct dri_state *)ctx->drm_state; 168 169 free_drawable_hashtable(ctx); 170 171 if (dri_state->base.fd >= 0); 172 close(dri_state->base.fd); 173 } 174 175 Bool 176 isDRI2Connected(VADriverContextP ctx, char **driver_name) 177 { 178 struct dri_state *dri_state = (struct dri_state *)ctx->drm_state; 179 int major, minor; 180 int error_base; 181 int event_base; 182 char *device_name = NULL; 183 drm_magic_t magic; 184 *driver_name = NULL; 185 dri_state->base.fd = -1; 186 dri_state->base.auth_type = VA_NONE; 187 if (!VA_DRI2QueryExtension(ctx->native_dpy, &event_base, &error_base)) 188 goto err_out; 189 190 if (!VA_DRI2QueryVersion(ctx->native_dpy, &major, &minor)) 191 goto err_out; 192 193 194 if (!VA_DRI2Connect(ctx->native_dpy, RootWindow(ctx->native_dpy, ctx->x11_screen), 195 driver_name, &device_name) || !device_name) 196 goto err_out; 197 198 dri_state->base.fd = open(device_name, O_RDWR); 199 assert(dri_state->base.fd >= 0); 200 201 if (dri_state->base.fd < 0) 202 goto err_out; 203 204 if (drmGetMagic(dri_state->base.fd, &magic)) 205 goto err_out; 206 207 if (!VA_DRI2Authenticate(ctx->native_dpy, RootWindow(ctx->native_dpy, ctx->x11_screen), 208 magic)) 209 goto err_out; 210 211 dri_state->base.auth_type = VA_DRI2; 212 dri_state->createDrawable = dri2CreateDrawable; 213 dri_state->destroyDrawable = dri2DestroyDrawable; 214 dri_state->swapBuffer = dri2SwapBuffer; 215 dri_state->getRenderingBuffer = dri2GetRenderingBuffer; 216 dri_state->close = dri2Close; 217 gsDRI2SwapAvailable = (minor >= 2); 218 219 Xfree(device_name); 220 221 return True; 222 223 err_out: 224 if (device_name) 225 Xfree(device_name); 226 227 if (*driver_name) 228 Xfree(*driver_name); 229 230 if (dri_state->base.fd >= 0) 231 close(dri_state->base.fd); 232 233 *driver_name = NULL; 234 dri_state->base.fd = -1; 235 236 return False; 237 } 238 239