buffer.c revision 7ec681f3
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
38VAStatus
39vlVaCreateBuffer(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
74VAStatus
75vlVaBufferSetNumElements(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
104VAStatus
105vlVaMapBuffer(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
156VAStatus
157vlVaUnmapBuffer(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
190VAStatus
191vlVaDestroyBuffer(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
222VAStatus
223vlVaBufferInfo(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
246VAStatus
247vlVaAcquireBufferHandle(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
342VAStatus
343vlVaReleaseBufferHandle(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