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