1 /**************************************************************************
2  *
3  * Copyright 2010 Thomas Balling Sørensen & 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 "frontend/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
vlVaCreateBuffer(VADriverContextP ctx,VAContextID context,VABufferType type,unsigned int size,unsigned int num_elements,void * data,VABufferID * buf_id)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
vlVaBufferSetNumElements(VADriverContextP ctx,VABufferID buf_id,unsigned int num_elements)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
vlVaMapBuffer(VADriverContextP ctx,VABufferID buf_id,void ** pbuff)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->buffer_map(drv->pipe, resource, 0, PIPE_MAP_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
vlVaUnmapBuffer(VADriverContextP ctx,VABufferID buf_id)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
vlVaDestroyBuffer(VADriverContextP ctx,VABufferID buf_id)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       if (buf->derived_image_buffer)
211          buf->derived_image_buffer->destroy(buf->derived_image_buffer);
212    }
213 
214    FREE(buf->data);
215    FREE(buf);
216    handle_table_remove(VL_VA_DRIVER(ctx)->htab, buf_id);
217    mtx_unlock(&drv->mutex);
218 
219    return VA_STATUS_SUCCESS;
220 }
221 
222 VAStatus
vlVaBufferInfo(VADriverContextP ctx,VABufferID buf_id,VABufferType * type,unsigned int * size,unsigned int * num_elements)223 vlVaBufferInfo(VADriverContextP ctx, VABufferID buf_id, VABufferType *type,
224                unsigned int *size, unsigned int *num_elements)
225 {
226    vlVaDriver *drv;
227    vlVaBuffer *buf;
228 
229    if (!ctx)
230       return VA_STATUS_ERROR_INVALID_CONTEXT;
231 
232    drv = VL_VA_DRIVER(ctx);
233    mtx_lock(&drv->mutex);
234    buf = handle_table_get(drv->htab, buf_id);
235    mtx_unlock(&drv->mutex);
236    if (!buf)
237       return VA_STATUS_ERROR_INVALID_BUFFER;
238 
239    *type = buf->type;
240    *size = buf->size;
241    *num_elements = buf->num_elements;
242 
243    return VA_STATUS_SUCCESS;
244 }
245 
246 VAStatus
vlVaAcquireBufferHandle(VADriverContextP ctx,VABufferID buf_id,VABufferInfo * out_buf_info)247 vlVaAcquireBufferHandle(VADriverContextP ctx, VABufferID buf_id,
248                         VABufferInfo *out_buf_info)
249 {
250    vlVaDriver *drv;
251    uint32_t i;
252    uint32_t mem_type;
253    vlVaBuffer *buf ;
254    struct pipe_screen *screen;
255 
256    /* List of supported memory types, in preferred order. */
257    static const uint32_t mem_types[] = {
258       VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
259       0
260    };
261 
262    if (!ctx)
263       return VA_STATUS_ERROR_INVALID_CONTEXT;
264 
265    drv = VL_VA_DRIVER(ctx);
266    screen = VL_VA_PSCREEN(ctx);
267    mtx_lock(&drv->mutex);
268    buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id);
269    mtx_unlock(&drv->mutex);
270 
271    if (!buf)
272       return VA_STATUS_ERROR_INVALID_BUFFER;
273 
274    /* Only VA surface|image like buffers are supported for now .*/
275    if (buf->type != VAImageBufferType)
276       return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
277 
278    if (!out_buf_info)
279       return VA_STATUS_ERROR_INVALID_PARAMETER;
280 
281    if (!out_buf_info->mem_type)
282       mem_type = mem_types[0];
283    else {
284       mem_type = 0;
285       for (i = 0; mem_types[i] != 0; i++) {
286          if (out_buf_info->mem_type & mem_types[i]) {
287             mem_type = out_buf_info->mem_type;
288             break;
289          }
290       }
291       if (!mem_type)
292          return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
293    }
294 
295    if (!buf->derived_surface.resource)
296       return VA_STATUS_ERROR_INVALID_BUFFER;
297 
298    if (buf->export_refcount > 0) {
299       if (buf->export_state.mem_type != mem_type)
300          return VA_STATUS_ERROR_INVALID_PARAMETER;
301    } else {
302       VABufferInfo * const buf_info = &buf->export_state;
303 
304       switch (mem_type) {
305       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: {
306          struct winsys_handle whandle;
307 
308          mtx_lock(&drv->mutex);
309          drv->pipe->flush(drv->pipe, NULL, 0);
310 
311          memset(&whandle, 0, sizeof(whandle));
312          whandle.type = WINSYS_HANDLE_TYPE_FD;
313 
314          if (!screen->resource_get_handle(screen, drv->pipe,
315                                           buf->derived_surface.resource,
316                                           &whandle, PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE)) {
317             mtx_unlock(&drv->mutex);
318             return VA_STATUS_ERROR_INVALID_BUFFER;
319          }
320 
321          mtx_unlock(&drv->mutex);
322 
323          buf_info->handle = (intptr_t)whandle.handle;
324          break;
325       }
326       default:
327          return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
328       }
329 
330       buf_info->type = buf->type;
331       buf_info->mem_type = mem_type;
332       buf_info->mem_size = buf->num_elements * buf->size;
333    }
334 
335    buf->export_refcount++;
336 
337    *out_buf_info = buf->export_state;
338 
339    return VA_STATUS_SUCCESS;
340 }
341 
342 VAStatus
vlVaReleaseBufferHandle(VADriverContextP ctx,VABufferID buf_id)343 vlVaReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id)
344 {
345    vlVaDriver *drv;
346    vlVaBuffer *buf;
347 
348    if (!ctx)
349       return VA_STATUS_ERROR_INVALID_CONTEXT;
350 
351    drv = VL_VA_DRIVER(ctx);
352    mtx_lock(&drv->mutex);
353    buf = handle_table_get(drv->htab, buf_id);
354    mtx_unlock(&drv->mutex);
355 
356    if (!buf)
357       return VA_STATUS_ERROR_INVALID_BUFFER;
358 
359    if (buf->export_refcount == 0)
360       return VA_STATUS_ERROR_INVALID_BUFFER;
361 
362    if (--buf->export_refcount == 0) {
363       VABufferInfo * const buf_info = &buf->export_state;
364 
365       switch (buf_info->mem_type) {
366       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
367          close((intptr_t)buf_info->handle);
368          break;
369       default:
370          return VA_STATUS_ERROR_INVALID_BUFFER;
371       }
372 
373       buf_info->mem_type = 0;
374    }
375 
376    return VA_STATUS_SUCCESS;
377 }
378