Merge ../mesa into vulkan
[mesa.git] / src / gallium / state_trackers / va / buffer.c
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 "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 } else {
137 pipe_mutex_unlock(drv->mutex);
138 *pbuff = buf->data;
139 }
140
141 return VA_STATUS_SUCCESS;
142 }
143
144 VAStatus
145 vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id)
146 {
147 vlVaDriver *drv;
148 vlVaBuffer *buf;
149
150 if (!ctx)
151 return VA_STATUS_ERROR_INVALID_CONTEXT;
152
153 drv = VL_VA_DRIVER(ctx);
154 if (!drv)
155 return VA_STATUS_ERROR_INVALID_CONTEXT;
156
157 pipe_mutex_lock(drv->mutex);
158 buf = handle_table_get(drv->htab, buf_id);
159 if (!buf || buf->export_refcount > 0) {
160 pipe_mutex_unlock(drv->mutex);
161 return VA_STATUS_ERROR_INVALID_BUFFER;
162 }
163
164 if (buf->derived_surface.resource) {
165 if (!buf->derived_surface.transfer) {
166 pipe_mutex_unlock(drv->mutex);
167 return VA_STATUS_ERROR_INVALID_BUFFER;
168 }
169
170 pipe_buffer_unmap(drv->pipe, buf->derived_surface.transfer);
171 buf->derived_surface.transfer = NULL;
172 }
173 pipe_mutex_unlock(drv->mutex);
174
175 return VA_STATUS_SUCCESS;
176 }
177
178 VAStatus
179 vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id)
180 {
181 vlVaDriver *drv;
182 vlVaBuffer *buf;
183
184 if (!ctx)
185 return VA_STATUS_ERROR_INVALID_CONTEXT;
186
187 drv = VL_VA_DRIVER(ctx);
188 pipe_mutex_lock(drv->mutex);
189 buf = handle_table_get(drv->htab, buf_id);
190 if (!buf) {
191 pipe_mutex_unlock(drv->mutex);
192 return VA_STATUS_ERROR_INVALID_BUFFER;
193 }
194
195 if (buf->derived_surface.resource) {
196 if (buf->export_refcount > 0) {
197 pipe_mutex_unlock(drv->mutex);
198 return VA_STATUS_ERROR_INVALID_BUFFER;
199 }
200
201 pipe_resource_reference(&buf->derived_surface.resource, NULL);
202 }
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 pipe_mutex_unlock(drv->mutex);
301
302 memset(&whandle, 0, sizeof(whandle));
303 whandle.type = DRM_API_HANDLE_TYPE_FD;
304
305 if (!screen->resource_get_handle(screen, buf->derived_surface.resource, &whandle))
306 return VA_STATUS_ERROR_INVALID_BUFFER;
307
308 buf_info->handle = (intptr_t)whandle.handle;
309 break;
310 }
311 default:
312 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
313 }
314
315 buf_info->type = buf->type;
316 buf_info->mem_type = mem_type;
317 buf_info->mem_size = buf->num_elements * buf->size;
318 }
319
320 buf->export_refcount++;
321
322 *out_buf_info = buf->export_state;
323
324 return VA_STATUS_SUCCESS;
325 }
326
327 VAStatus
328 vlVaReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id)
329 {
330 vlVaDriver *drv;
331 vlVaBuffer *buf;
332
333 if (!ctx)
334 return VA_STATUS_ERROR_INVALID_CONTEXT;
335
336 drv = VL_VA_DRIVER(ctx);
337 pipe_mutex_lock(drv->mutex);
338 buf = handle_table_get(drv->htab, buf_id);
339 pipe_mutex_unlock(drv->mutex);
340
341 if (!buf)
342 return VA_STATUS_ERROR_INVALID_BUFFER;
343
344 if (buf->export_refcount == 0)
345 return VA_STATUS_ERROR_INVALID_BUFFER;
346
347 if (--buf->export_refcount == 0) {
348 VABufferInfo * const buf_info = &buf->export_state;
349
350 switch (buf_info->mem_type) {
351 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
352 close((intptr_t)buf_info->handle);
353 break;
354 default:
355 return VA_STATUS_ERROR_INVALID_BUFFER;
356 }
357
358 buf_info->mem_type = 0;
359 }
360
361 return VA_STATUS_SUCCESS;
362 }