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 mtx_lock(&drv->mutex); 68 *buf_id = handle_table_add(drv->htab, buf); 69 mtx_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 mtx_lock(&drv->mutex); 86 buf = handle_table_get(drv->htab, buf_id); 87 mtx_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 mtx_lock(&drv->mutex); 121 buf = handle_table_get(drv->htab, buf_id); 122 if (!buf || buf->export_refcount > 0) { 123 mtx_unlock(&drv->mutex); 124 return VA_STATUS_ERROR_INVALID_BUFFER; 125 } 126 127 if (buf->derived_surface.resource) { 128 struct pipe_resource *resource; 129 struct pipe_box box = {}; 130 131 resource = buf->derived_surface.resource; 132 box.width = resource->width0; 133 box.height = resource->height0; 134 box.depth = resource->depth0; 135 *pbuff = drv->pipe->transfer_map(drv->pipe, resource, 0, PIPE_TRANSFER_WRITE, 136 &box, &buf->derived_surface.transfer); 137 mtx_unlock(&drv->mutex); 138 139 if (!buf->derived_surface.transfer || !*pbuff) 140 return VA_STATUS_ERROR_INVALID_BUFFER; 141 142 if (buf->type == VAEncCodedBufferType) { 143 ((VACodedBufferSegment*)buf->data)->buf = *pbuff; 144 ((VACodedBufferSegment*)buf->data)->size = buf->coded_size; 145 ((VACodedBufferSegment*)buf->data)->next = NULL; 146 *pbuff = buf->data; 147 } 148 } else { 149 mtx_unlock(&drv->mutex); 150 *pbuff = buf->data; 151 } 152 153 return VA_STATUS_SUCCESS; 154 } 155 156 VAStatus 157 vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id) 158 { 159 vlVaDriver *drv; 160 vlVaBuffer *buf; 161 162 if (!ctx) 163 return VA_STATUS_ERROR_INVALID_CONTEXT; 164 165 drv = VL_VA_DRIVER(ctx); 166 if (!drv) 167 return VA_STATUS_ERROR_INVALID_CONTEXT; 168 169 mtx_lock(&drv->mutex); 170 buf = handle_table_get(drv->htab, buf_id); 171 if (!buf || buf->export_refcount > 0) { 172 mtx_unlock(&drv->mutex); 173 return VA_STATUS_ERROR_INVALID_BUFFER; 174 } 175 176 if (buf->derived_surface.resource) { 177 if (!buf->derived_surface.transfer) { 178 mtx_unlock(&drv->mutex); 179 return VA_STATUS_ERROR_INVALID_BUFFER; 180 } 181 182 pipe_buffer_unmap(drv->pipe, buf->derived_surface.transfer); 183 buf->derived_surface.transfer = NULL; 184 } 185 mtx_unlock(&drv->mutex); 186 187 return VA_STATUS_SUCCESS; 188 } 189 190 VAStatus 191 vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id) 192 { 193 vlVaDriver *drv; 194 vlVaBuffer *buf; 195 196 if (!ctx) 197 return VA_STATUS_ERROR_INVALID_CONTEXT; 198 199 drv = VL_VA_DRIVER(ctx); 200 mtx_lock(&drv->mutex); 201 buf = handle_table_get(drv->htab, buf_id); 202 if (!buf) { 203 mtx_unlock(&drv->mutex); 204 return VA_STATUS_ERROR_INVALID_BUFFER; 205 } 206 207 if (buf->derived_surface.resource) 208 pipe_resource_reference(&buf->derived_surface.resource, NULL); 209 210 FREE(buf->data); 211 FREE(buf); 212 handle_table_remove(VL_VA_DRIVER(ctx)->htab, buf_id); 213 mtx_unlock(&drv->mutex); 214 215 return VA_STATUS_SUCCESS; 216 } 217 218 VAStatus 219 vlVaBufferInfo(VADriverContextP ctx, VABufferID buf_id, VABufferType *type, 220 unsigned int *size, unsigned int *num_elements) 221 { 222 vlVaDriver *drv; 223 vlVaBuffer *buf; 224 225 if (!ctx) 226 return VA_STATUS_ERROR_INVALID_CONTEXT; 227 228 drv = VL_VA_DRIVER(ctx); 229 mtx_lock(&drv->mutex); 230 buf = handle_table_get(drv->htab, buf_id); 231 mtx_unlock(&drv->mutex); 232 if (!buf) 233 return VA_STATUS_ERROR_INVALID_BUFFER; 234 235 *type = buf->type; 236 *size = buf->size; 237 *num_elements = buf->num_elements; 238 239 return VA_STATUS_SUCCESS; 240 } 241 242 VAStatus 243 vlVaAcquireBufferHandle(VADriverContextP ctx, VABufferID buf_id, 244 VABufferInfo *out_buf_info) 245 { 246 vlVaDriver *drv; 247 uint32_t i; 248 uint32_t mem_type; 249 vlVaBuffer *buf ; 250 struct pipe_screen *screen; 251 252 /* List of supported memory types, in preferred order. */ 253 static const uint32_t mem_types[] = { 254 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME, 255 0 256 }; 257 258 if (!ctx) 259 return VA_STATUS_ERROR_INVALID_CONTEXT; 260 261 drv = VL_VA_DRIVER(ctx); 262 screen = VL_VA_PSCREEN(ctx); 263 mtx_lock(&drv->mutex); 264 buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id); 265 mtx_unlock(&drv->mutex); 266 267 if (!buf) 268 return VA_STATUS_ERROR_INVALID_BUFFER; 269 270 /* Only VA surface|image like buffers are supported for now .*/ 271 if (buf->type != VAImageBufferType) 272 return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE; 273 274 if (!out_buf_info) 275 return VA_STATUS_ERROR_INVALID_PARAMETER; 276 277 if (!out_buf_info->mem_type) 278 mem_type = mem_types[0]; 279 else { 280 mem_type = 0; 281 for (i = 0; mem_types[i] != 0; i++) { 282 if (out_buf_info->mem_type & mem_types[i]) { 283 mem_type = out_buf_info->mem_type; 284 break; 285 } 286 } 287 if (!mem_type) 288 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE; 289 } 290 291 if (!buf->derived_surface.resource) 292 return VA_STATUS_ERROR_INVALID_BUFFER; 293 294 if (buf->export_refcount > 0) { 295 if (buf->export_state.mem_type != mem_type) 296 return VA_STATUS_ERROR_INVALID_PARAMETER; 297 } else { 298 VABufferInfo * const buf_info = &buf->export_state; 299 300 switch (mem_type) { 301 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: { 302 struct winsys_handle whandle; 303 304 mtx_lock(&drv->mutex); 305 drv->pipe->flush(drv->pipe, NULL, 0); 306 307 memset(&whandle, 0, sizeof(whandle)); 308 whandle.type = DRM_API_HANDLE_TYPE_FD; 309 310 if (!screen->resource_get_handle(screen, drv->pipe, 311 buf->derived_surface.resource, 312 &whandle, PIPE_HANDLE_USAGE_READ_WRITE)) { 313 mtx_unlock(&drv->mutex); 314 return VA_STATUS_ERROR_INVALID_BUFFER; 315 } 316 317 mtx_unlock(&drv->mutex); 318 319 buf_info->handle = (intptr_t)whandle.handle; 320 break; 321 } 322 default: 323 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE; 324 } 325 326 buf_info->type = buf->type; 327 buf_info->mem_type = mem_type; 328 buf_info->mem_size = buf->num_elements * buf->size; 329 } 330 331 buf->export_refcount++; 332 333 *out_buf_info = buf->export_state; 334 335 return VA_STATUS_SUCCESS; 336 } 337 338 VAStatus 339 vlVaReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id) 340 { 341 vlVaDriver *drv; 342 vlVaBuffer *buf; 343 344 if (!ctx) 345 return VA_STATUS_ERROR_INVALID_CONTEXT; 346 347 drv = VL_VA_DRIVER(ctx); 348 mtx_lock(&drv->mutex); 349 buf = handle_table_get(drv->htab, buf_id); 350 mtx_unlock(&drv->mutex); 351 352 if (!buf) 353 return VA_STATUS_ERROR_INVALID_BUFFER; 354 355 if (buf->export_refcount == 0) 356 return VA_STATUS_ERROR_INVALID_BUFFER; 357 358 if (--buf->export_refcount == 0) { 359 VABufferInfo * const buf_info = &buf->export_state; 360 361 switch (buf_info->mem_type) { 362 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: 363 close((intptr_t)buf_info->handle); 364 break; 365 default: 366 return VA_STATUS_ERROR_INVALID_BUFFER; 367 } 368 369 buf_info->mem_type = 0; 370 } 371 372 return VA_STATUS_SUCCESS; 373 } 374