1 /************************************************************************** 2 * 3 * Copyright 2010 Thomas Balling Srensen & Orasanu Lucian. 4 * Copyright 2014 Advanced Micro Devices, Inc. 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22 * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 **************************************************************************/ 28 29 #include "pipe/p_screen.h" 30 #include "state_tracker/drm_driver.h" 31 #include "util/u_memory.h" 32 #include "util/u_handle_table.h" 33 #include "util/u_transfer.h" 34 #include "vl/vl_winsys.h" 35 36 #include "va_private.h" 37 38 VAStatus 39 vlVaCreateBuffer(VADriverContextP ctx, VAContextID context, VABufferType type, 40 unsigned int size, unsigned int num_elements, void *data, 41 VABufferID *buf_id) 42 { 43 vlVaDriver *drv; 44 vlVaBuffer *buf; 45 46 if (!ctx) 47 return VA_STATUS_ERROR_INVALID_CONTEXT; 48 49 buf = CALLOC(1, sizeof(vlVaBuffer)); 50 if (!buf) 51 return VA_STATUS_ERROR_ALLOCATION_FAILED; 52 53 buf->type = type; 54 buf->size = size; 55 buf->num_elements = num_elements; 56 buf->data = MALLOC(size * num_elements); 57 58 if (!buf->data) { 59 FREE(buf); 60 return VA_STATUS_ERROR_ALLOCATION_FAILED; 61 } 62 63 if (data) 64 memcpy(buf->data, data, size * num_elements); 65 66 drv = VL_VA_DRIVER(ctx); 67 pipe_mutex_lock(drv->mutex); 68 *buf_id = handle_table_add(drv->htab, buf); 69 pipe_mutex_unlock(drv->mutex); 70 71 return VA_STATUS_SUCCESS; 72 } 73 74 VAStatus 75 vlVaBufferSetNumElements(VADriverContextP ctx, VABufferID buf_id, 76 unsigned int num_elements) 77 { 78 vlVaDriver *drv; 79 vlVaBuffer *buf; 80 81 if (!ctx) 82 return VA_STATUS_ERROR_INVALID_CONTEXT; 83 84 drv = VL_VA_DRIVER(ctx); 85 pipe_mutex_lock(drv->mutex); 86 buf = handle_table_get(drv->htab, buf_id); 87 pipe_mutex_unlock(drv->mutex); 88 if (!buf) 89 return VA_STATUS_ERROR_INVALID_BUFFER; 90 91 if (buf->derived_surface.resource) 92 return VA_STATUS_ERROR_INVALID_BUFFER; 93 94 buf->data = REALLOC(buf->data, buf->size * buf->num_elements, 95 buf->size * num_elements); 96 buf->num_elements = num_elements; 97 98 if (!buf->data) 99 return VA_STATUS_ERROR_ALLOCATION_FAILED; 100 101 return VA_STATUS_SUCCESS; 102 } 103 104 VAStatus 105 vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff) 106 { 107 vlVaDriver *drv; 108 vlVaBuffer *buf; 109 110 if (!ctx) 111 return VA_STATUS_ERROR_INVALID_CONTEXT; 112 113 drv = VL_VA_DRIVER(ctx); 114 if (!drv) 115 return VA_STATUS_ERROR_INVALID_CONTEXT; 116 117 if (!pbuff) 118 return VA_STATUS_ERROR_INVALID_PARAMETER; 119 120 pipe_mutex_lock(drv->mutex); 121 buf = handle_table_get(drv->htab, buf_id); 122 if (!buf || buf->export_refcount > 0) { 123 pipe_mutex_unlock(drv->mutex); 124 return VA_STATUS_ERROR_INVALID_BUFFER; 125 } 126 127 if (buf->derived_surface.resource) { 128 *pbuff = pipe_buffer_map(drv->pipe, buf->derived_surface.resource, 129 PIPE_TRANSFER_WRITE, 130 &buf->derived_surface.transfer); 131 pipe_mutex_unlock(drv->mutex); 132 133 if (!buf->derived_surface.transfer || !*pbuff) 134 return VA_STATUS_ERROR_INVALID_BUFFER; 135 136 if (buf->type == VAEncCodedBufferType) { 137 ((VACodedBufferSegment*)buf->data)->buf = *pbuff; 138 ((VACodedBufferSegment*)buf->data)->size = buf->coded_size; 139 ((VACodedBufferSegment*)buf->data)->next = NULL; 140 *pbuff = buf->data; 141 } 142 } else { 143 pipe_mutex_unlock(drv->mutex); 144 *pbuff = buf->data; 145 } 146 147 return VA_STATUS_SUCCESS; 148 } 149 150 VAStatus 151 vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id) 152 { 153 vlVaDriver *drv; 154 vlVaBuffer *buf; 155 156 if (!ctx) 157 return VA_STATUS_ERROR_INVALID_CONTEXT; 158 159 drv = VL_VA_DRIVER(ctx); 160 if (!drv) 161 return VA_STATUS_ERROR_INVALID_CONTEXT; 162 163 pipe_mutex_lock(drv->mutex); 164 buf = handle_table_get(drv->htab, buf_id); 165 if (!buf || buf->export_refcount > 0) { 166 pipe_mutex_unlock(drv->mutex); 167 return VA_STATUS_ERROR_INVALID_BUFFER; 168 } 169 170 if (buf->derived_surface.resource) { 171 if (!buf->derived_surface.transfer) { 172 pipe_mutex_unlock(drv->mutex); 173 return VA_STATUS_ERROR_INVALID_BUFFER; 174 } 175 176 pipe_buffer_unmap(drv->pipe, buf->derived_surface.transfer); 177 buf->derived_surface.transfer = NULL; 178 } 179 pipe_mutex_unlock(drv->mutex); 180 181 return VA_STATUS_SUCCESS; 182 } 183 184 VAStatus 185 vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id) 186 { 187 vlVaDriver *drv; 188 vlVaBuffer *buf; 189 190 if (!ctx) 191 return VA_STATUS_ERROR_INVALID_CONTEXT; 192 193 drv = VL_VA_DRIVER(ctx); 194 pipe_mutex_lock(drv->mutex); 195 buf = handle_table_get(drv->htab, buf_id); 196 if (!buf) { 197 pipe_mutex_unlock(drv->mutex); 198 return VA_STATUS_ERROR_INVALID_BUFFER; 199 } 200 201 if (buf->derived_surface.resource) 202 pipe_resource_reference(&buf->derived_surface.resource, NULL); 203 204 FREE(buf->data); 205 FREE(buf); 206 handle_table_remove(VL_VA_DRIVER(ctx)->htab, buf_id); 207 pipe_mutex_unlock(drv->mutex); 208 209 return VA_STATUS_SUCCESS; 210 } 211 212 VAStatus 213 vlVaBufferInfo(VADriverContextP ctx, VABufferID buf_id, VABufferType *type, 214 unsigned int *size, unsigned int *num_elements) 215 { 216 vlVaDriver *drv; 217 vlVaBuffer *buf; 218 219 if (!ctx) 220 return VA_STATUS_ERROR_INVALID_CONTEXT; 221 222 drv = VL_VA_DRIVER(ctx); 223 pipe_mutex_lock(drv->mutex); 224 buf = handle_table_get(drv->htab, buf_id); 225 pipe_mutex_unlock(drv->mutex); 226 if (!buf) 227 return VA_STATUS_ERROR_INVALID_BUFFER; 228 229 *type = buf->type; 230 *size = buf->size; 231 *num_elements = buf->num_elements; 232 233 return VA_STATUS_SUCCESS; 234 } 235 236 VAStatus 237 vlVaAcquireBufferHandle(VADriverContextP ctx, VABufferID buf_id, 238 VABufferInfo *out_buf_info) 239 { 240 vlVaDriver *drv; 241 uint32_t i; 242 uint32_t mem_type; 243 vlVaBuffer *buf ; 244 struct pipe_screen *screen; 245 246 /* List of supported memory types, in preferred order. */ 247 static const uint32_t mem_types[] = { 248 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME, 249 0 250 }; 251 252 if (!ctx) 253 return VA_STATUS_ERROR_INVALID_CONTEXT; 254 255 drv = VL_VA_DRIVER(ctx); 256 screen = VL_VA_PSCREEN(ctx); 257 pipe_mutex_lock(drv->mutex); 258 buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id); 259 pipe_mutex_unlock(drv->mutex); 260 261 if (!buf) 262 return VA_STATUS_ERROR_INVALID_BUFFER; 263 264 /* Only VA surface|image like buffers are supported for now .*/ 265 if (buf->type != VAImageBufferType) 266 return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE; 267 268 if (!out_buf_info) 269 return VA_STATUS_ERROR_INVALID_PARAMETER; 270 271 if (!out_buf_info->mem_type) 272 mem_type = mem_types[0]; 273 else { 274 mem_type = 0; 275 for (i = 0; mem_types[i] != 0; i++) { 276 if (out_buf_info->mem_type & mem_types[i]) { 277 mem_type = out_buf_info->mem_type; 278 break; 279 } 280 } 281 if (!mem_type) 282 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE; 283 } 284 285 if (!buf->derived_surface.resource) 286 return VA_STATUS_ERROR_INVALID_BUFFER; 287 288 if (buf->export_refcount > 0) { 289 if (buf->export_state.mem_type != mem_type) 290 return VA_STATUS_ERROR_INVALID_PARAMETER; 291 } else { 292 VABufferInfo * const buf_info = &buf->export_state; 293 294 switch (mem_type) { 295 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: { 296 struct winsys_handle whandle; 297 298 pipe_mutex_lock(drv->mutex); 299 drv->pipe->flush(drv->pipe, NULL, 0); 300 301 memset(&whandle, 0, sizeof(whandle)); 302 whandle.type = DRM_API_HANDLE_TYPE_FD; 303 304 if (!screen->resource_get_handle(screen, drv->pipe, 305 buf->derived_surface.resource, 306 &whandle, PIPE_HANDLE_USAGE_READ_WRITE)) { 307 pipe_mutex_unlock(drv->mutex); 308 return VA_STATUS_ERROR_INVALID_BUFFER; 309 } 310 311 pipe_mutex_unlock(drv->mutex); 312 313 buf_info->handle = (intptr_t)whandle.handle; 314 break; 315 } 316 default: 317 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE; 318 } 319 320 buf_info->type = buf->type; 321 buf_info->mem_type = mem_type; 322 buf_info->mem_size = buf->num_elements * buf->size; 323 } 324 325 buf->export_refcount++; 326 327 *out_buf_info = buf->export_state; 328 329 return VA_STATUS_SUCCESS; 330 } 331 332 VAStatus 333 vlVaReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id) 334 { 335 vlVaDriver *drv; 336 vlVaBuffer *buf; 337 338 if (!ctx) 339 return VA_STATUS_ERROR_INVALID_CONTEXT; 340 341 drv = VL_VA_DRIVER(ctx); 342 pipe_mutex_lock(drv->mutex); 343 buf = handle_table_get(drv->htab, buf_id); 344 pipe_mutex_unlock(drv->mutex); 345 346 if (!buf) 347 return VA_STATUS_ERROR_INVALID_BUFFER; 348 349 if (buf->export_refcount == 0) 350 return VA_STATUS_ERROR_INVALID_BUFFER; 351 352 if (--buf->export_refcount == 0) { 353 VABufferInfo * const buf_info = &buf->export_state; 354 355 switch (buf_info->mem_type) { 356 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: 357 close((intptr_t)buf_info->handle); 358 break; 359 default: 360 return VA_STATUS_ERROR_INVALID_BUFFER; 361 } 362 363 buf_info->mem_type = 0; 364 } 365 366 return VA_STATUS_SUCCESS; 367 } 368