Array bound check
[platform/upstream/libva.git] / va / egl / va_egl_impl.c
1 #define _GNU_SOURCE 1
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdarg.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <dlfcn.h>
8
9 #include "va_egl_private.h"
10 #include "va_egl_impl.h"
11
12 static int 
13 check_extension(const char *name, const char *exts)
14 {
15     const char *end;
16     int name_len, n;
17
18     if (!name || !exts)
19         return 0;
20
21     end = exts + strlen(exts);
22     name_len = strlen(name);
23
24     while (exts < end) {
25         n = strcspn(exts, " ");
26
27         if (n == name_len && strncmp(name, exts, n) == 0)
28             return 1;
29
30         exts += (n + 1);
31     }
32
33     return 0;
34 }
35
36 static int 
37 check_pixmap_extensions(VADriverContextP ctx, EGLDisplay egl_display)
38 {
39     const char *exts;
40
41     exts = (const char *)eglQueryString(egl_display, EGL_EXTENSIONS);
42
43     if (!check_extension("EGL_KHR_image_pixmap", exts))
44         return 0;
45
46     return 1;
47 }
48
49 /* ========================================================================= */
50 /* === VA/EGL implementation from the driver (fordward calls)            === */
51 /* ========================================================================= */
52 #ifdef INVOKE
53 #undef INVOKE
54 #endif
55
56 #define INVOKE(ctx, func, args) do {                    \
57         VADriverVTableEGLP vtable = (ctx)->vtable_egl;  \
58         if (!vtable->va##func##EGL)                     \
59             return VA_STATUS_ERROR_UNIMPLEMENTED;       \
60                                                         \
61         VAStatus status = vtable->va##func##EGL args;   \
62         if (status != VA_STATUS_SUCCESS)                \
63             return status;                              \
64     } while (0)
65
66
67 static VAStatus
68 vaQuerySurfaceTargetsEGL_impl_driver(VADisplay dpy,
69                                      EGLenum *target_list,
70                                      int *num_targets)
71 {
72     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
73
74     INVOKE(ctx, QuerySurfaceTargets, (ctx, target_list, num_targets));
75
76     return VA_STATUS_SUCCESS;
77 }
78
79 static VAStatus 
80 vaCreateSurfaceEGL_impl_driver(VADisplay dpy,
81                                EGLenum target,
82                                unsigned int width,
83                                unsigned int height,
84                                VASurfaceEGL *gl_surface)
85 {
86     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
87
88     INVOKE(ctx, CreateSurface, (ctx, target, width, height, gl_surface));
89
90     return VA_STATUS_SUCCESS;
91 }
92
93 static VAStatus
94 vaDestroySurfaceEGL_impl_driver(VADisplay dpy, VASurfaceEGL egl_surface)
95 {
96     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
97
98     INVOKE(ctx, DestroySurface, (ctx, egl_surface));
99
100     return VA_STATUS_SUCCESS;
101 }
102
103 static VAStatus
104 vaAssociateSurfaceEGL_impl_driver(VADisplay dpy,
105                                   VASurfaceEGL egl_surface,
106                                   VASurfaceID surface,
107                                   unsigned int flags)
108 {
109     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
110
111     INVOKE(ctx, AssociateSurface, (ctx, egl_surface, surface, flags));
112
113     return VA_STATUS_SUCCESS;
114 }
115
116 static VAStatus
117 vaSyncSurfaceEGL_impl_driver(VADisplay dpy,
118                              VASurfaceEGL egl_surface)
119 {
120     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
121
122     INVOKE(ctx, SyncSurface, (ctx, egl_surface));
123
124     return VA_STATUS_SUCCESS;
125 }
126
127 static VAStatus
128 vaGetSurfaceInfoEGL_impl_driver(VADisplay dpy,
129                                 VASurfaceEGL egl_surface,
130                                 EGLenum *target,
131                                 EGLClientBuffer *buffer,
132                                 EGLint *attrib_list,
133                                 int *num_attribs)
134 {
135     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
136
137     INVOKE(ctx, GetSurfaceInfo, (ctx, egl_surface, target, buffer, attrib_list, num_attribs));
138
139     return VA_STATUS_SUCCESS;
140 }
141
142 static VAStatus
143 vaDeassociateSurfaceEGL_impl_driver(VADisplay dpy,
144                                     VASurfaceEGL egl_surface)
145 {
146     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
147
148     INVOKE(ctx, DeassociateSurface, (ctx, egl_surface));
149
150     return VA_STATUS_SUCCESS;
151 }
152
153 #undef INVOKE
154
155 /* ========================================================================= */
156 /* === VA/EGL helpers                                                    === */
157 /* ========================================================================= */
158 /** Unique VASurfaceImplEGL identifier */
159 #define VA_SURFACE_IMPL_EGL_MAGIC VA_FOURCC('V','E','G','L')
160
161 struct VASurfaceImplEGL {
162     uint32_t            magic;      ///< Magic number identifying a VASurfaceImplEGL
163     VASurfaceID         surface;    ///< Associated VA surface
164     EGLenum             target;     ///< EGL target
165     EGLClientBuffer     buffer;
166     unsigned int        width;
167     unsigned int        height;
168     unsigned int        flags;
169 };
170
171 static void *
172 create_native_pixmap(VADisplay dpy, unsigned int width, unsigned int height)
173 {
174     VADisplayContextP pDisplayContext = (VADisplayContextP)dpy;
175     VAStatus status;
176     void *native_pixmap = NULL;
177
178     status = pDisplayContext->vaCreateNativePixmap(pDisplayContext, width, height, &native_pixmap);
179
180     if (status != VA_STATUS_SUCCESS)
181         native_pixmap = NULL;
182
183     return native_pixmap;
184 }
185
186 static void
187 destroy_native_pixmap(VADisplay dpy, void *native_pixmap)
188 {
189     VADisplayContextP pDisplayContext = (VADisplayContextP)dpy;
190     
191     pDisplayContext->vaFreeNativePixmap(pDisplayContext, native_pixmap);
192 }
193
194 // Check VASurfaceImplEGL is valid
195 static inline int check_surface(VASurfaceImplEGLP pSurfaceImplEGL)
196 {
197     return pSurfaceImplEGL && pSurfaceImplEGL->magic == VA_SURFACE_IMPL_EGL_MAGIC;
198 }
199
200 static inline VAStatus
201 deassociate_surface(VADriverContextP ctx, VASurfaceImplEGLP pSurfaceImplEGL)
202 {
203     pSurfaceImplEGL->surface = VA_INVALID_SURFACE;
204
205     return VA_STATUS_SUCCESS;
206 }
207
208 static VAStatus
209 associate_surface(VADriverContextP ctx,
210                   VASurfaceImplEGLP pSurfaceImplEGL,
211                   VASurfaceID surface,
212                   unsigned int flags)
213 {
214     VAStatus status;
215     status = deassociate_surface(ctx, pSurfaceImplEGL);
216
217     if (status != VA_STATUS_SUCCESS)
218         return status;
219
220     pSurfaceImplEGL->surface = surface;
221     pSurfaceImplEGL->flags = flags;
222
223     return VA_STATUS_SUCCESS;
224 }
225
226 static inline VAStatus
227 sync_surface(VADriverContextP ctx, VASurfaceImplEGLP pSurfaceImplEGL)
228 {
229     if (pSurfaceImplEGL->surface == VA_INVALID_SURFACE)
230         return VA_STATUS_ERROR_INVALID_SURFACE;
231
232     return ctx->vtable->vaSyncSurface(ctx, pSurfaceImplEGL->surface);
233 }
234
235 static VAStatus
236 sync_associated_surface(VADriverContextP ctx, VASurfaceImplEGLP pSurfaceImplEGL)
237 {
238     VAStatus status;
239
240     status = sync_surface(ctx, pSurfaceImplEGL);
241
242     if (status != VA_STATUS_SUCCESS)
243         return status;
244
245     if (pSurfaceImplEGL->target != EGL_NATIVE_PIXMAP_KHR)
246         return VA_STATUS_ERROR_UNIMPLEMENTED;
247
248     status = ctx->vtable->vaPutSurface(
249         ctx,
250         pSurfaceImplEGL->surface,
251         (void *)pSurfaceImplEGL->buffer,
252         0, 0, pSurfaceImplEGL->width, pSurfaceImplEGL->height,
253         0, 0, pSurfaceImplEGL->width, pSurfaceImplEGL->height,
254         NULL, 0,
255         pSurfaceImplEGL->flags
256         );
257
258     if (status == VA_STATUS_SUCCESS) {
259         eglWaitNative(EGL_CORE_NATIVE_ENGINE);
260     }
261
262     return status;
263 }
264
265 /* ========================================================================= */
266 /* === VA/EGL implementation from libVA (generic and suboptimal path)    === */
267 /* ========================================================================= */
268 #ifdef INIT_SURFACE
269 #undef INIT_SURFACE
270 #endif
271
272 #define INIT_SURFACE(surface, egl_surface) do {         \
273         surface = (VASurfaceImplEGLP)(egl_surface);     \
274         if (!check_surface(surface))                    \
275             return VA_STATUS_ERROR_INVALID_SURFACE;     \
276     } while (0)
277
278 static VAStatus
279 vaQuerySurfaceTargetsEGL_impl_libva(VADisplay dpy,
280                                     EGLenum *target_list,
281                                     int *num_targets)
282 {
283     int i = 0;
284
285     /* FIXME: support other targets ??? */
286     target_list[i++] = EGL_NATIVE_PIXMAP_KHR;
287     *num_targets = i;
288     assert(i <= IMPL_MAX_EGL_SURFACE_TARGETS);
289
290     return VA_STATUS_SUCCESS;
291 }
292
293 static VAStatus 
294 vaCreateSurfaceEGL_impl_libva(VADisplay dpy,
295                               EGLenum target,
296                               unsigned int width,
297                               unsigned int height,
298                               VASurfaceEGL *egl_surface)
299 {
300     VASurfaceImplEGLP pSurfaceImplEGL = NULL;
301
302     /* So far only support for EGL_NATIVE_PIXMAP_KHR */
303     if (target != 0 && target != EGL_NATIVE_PIXMAP_KHR)
304         return VA_STATUS_ERROR_INVALID_PARAMETER;
305
306     pSurfaceImplEGL = calloc(1, sizeof(*pSurfaceImplEGL));
307
308     if (!pSurfaceImplEGL) {
309         *egl_surface = 0;
310         return VA_STATUS_ERROR_ALLOCATION_FAILED;
311     }
312
313     pSurfaceImplEGL->magic = VA_SURFACE_IMPL_EGL_MAGIC;
314     pSurfaceImplEGL->surface = VA_INVALID_SURFACE;
315     pSurfaceImplEGL->target = target == 0 ? EGL_NATIVE_PIXMAP_KHR : target;
316     pSurfaceImplEGL->buffer = 0;
317     pSurfaceImplEGL->width = width;
318     pSurfaceImplEGL->height = height;
319     *egl_surface = (VASurfaceEGL)pSurfaceImplEGL;
320
321     return VA_STATUS_SUCCESS;
322 }
323
324 static VAStatus
325 vaDestroySurfaceEGL_impl_libva(VADisplay dpy, VASurfaceEGL egl_surface)
326 {
327     VASurfaceImplEGLP pSurfaceImplEGL;
328
329     INIT_SURFACE(pSurfaceImplEGL, egl_surface);
330
331     if (pSurfaceImplEGL->target == EGL_NATIVE_PIXMAP_KHR) {
332         if (pSurfaceImplEGL->buffer) {
333             destroy_native_pixmap(dpy, pSurfaceImplEGL->buffer);
334             pSurfaceImplEGL->buffer = 0;
335         }
336     }
337
338     free(pSurfaceImplEGL);
339
340     return VA_STATUS_SUCCESS;
341 }
342
343 static VAStatus
344 vaAssociateSurfaceEGL_impl_libva(
345     VADisplay dpy,
346     VASurfaceEGL egl_surface,
347     VASurfaceID surface,
348     unsigned int flags
349     )
350 {
351     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
352     VASurfaceImplEGLP pSurfaceImplEGL;
353     VAStatus status;
354
355     INIT_SURFACE(pSurfaceImplEGL, egl_surface);
356
357     if (surface == VA_INVALID_SURFACE)
358         return VA_STATUS_ERROR_INVALID_SURFACE;
359
360     if (pSurfaceImplEGL->target == EGL_NATIVE_PIXMAP_KHR) {
361         if (pSurfaceImplEGL->buffer)
362             destroy_native_pixmap(dpy, pSurfaceImplEGL->buffer);
363
364         pSurfaceImplEGL->buffer = create_native_pixmap(dpy, pSurfaceImplEGL->width, pSurfaceImplEGL->height);
365     }
366
367     pSurfaceImplEGL->surface = surface;
368     pSurfaceImplEGL->flags = flags;
369
370     if (pSurfaceImplEGL->buffer)
371         return VA_STATUS_SUCCESS;
372     
373     return VA_STATUS_ERROR_UNKNOWN;
374 }
375
376 static VAStatus
377 vaSyncSurfaceEGL_impl_libva(VADisplay dpy,
378                             VASurfaceEGL egl_surface)
379 {
380     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
381     VASurfaceImplEGLP pSurfaceImplEGL;
382     VAStatus status;
383
384     INIT_SURFACE(pSurfaceImplEGL, egl_surface);
385
386     status = sync_associated_surface(ctx, pSurfaceImplEGL);
387
388     return status;
389 }
390
391 static VAStatus
392 vaGetSurfaceInfoEGL_impl_libva(VADisplay dpy,
393                                VASurfaceEGL egl_surface,
394                                EGLenum *target,
395                                EGLClientBuffer *buffer,
396                                EGLint *attrib_list,
397                                int *num_attribs)
398 {
399     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
400     VASurfaceImplEGLP pSurfaceImplEGL;
401     VAStatus status;
402     int i = 0;
403
404     INIT_SURFACE(pSurfaceImplEGL, egl_surface);
405
406     if (pSurfaceImplEGL->surface == VA_INVALID_SURFACE)
407         return VA_STATUS_ERROR_INVALID_SURFACE;
408
409     if (*num_attribs < IMPL_MAX_EGL_SURFACE_ATTRIBUTES)
410         return VA_STATUS_ERROR_INVALID_PARAMETER;
411
412     *target = pSurfaceImplEGL->target;
413     *buffer = pSurfaceImplEGL->buffer;
414
415     if (pSurfaceImplEGL->target == EGL_NATIVE_PIXMAP_KHR) {
416         attrib_list[i++] = EGL_IMAGE_PRESERVED_KHR;
417         attrib_list[i + 1] = EGL_TRUE;
418         attrib_list[i++] = EGL_NONE;
419     } else {
420         /* FIXME later */
421         attrib_list[i++] = EGL_NONE;
422     }
423
424     *num_attribs = i;
425
426     return VA_STATUS_SUCCESS;
427 }
428
429 static VAStatus
430 vaDeassociateSurfaceEGL_impl_libva(
431     VADisplay dpy,
432     VASurfaceEGL egl_surface
433     )
434 {
435     VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
436     VASurfaceImplEGLP pSurfaceImplEGL;
437     VAStatus status;
438
439     INIT_SURFACE(pSurfaceImplEGL, egl_surface);
440
441     if (pSurfaceImplEGL->target == EGL_NATIVE_PIXMAP_KHR) {
442         if (pSurfaceImplEGL->buffer)
443             destroy_native_pixmap(dpy, pSurfaceImplEGL->buffer);
444
445         pSurfaceImplEGL->buffer = 0;
446     }
447
448     pSurfaceImplEGL->surface = VA_INVALID_SURFACE;
449
450     return VA_STATUS_SUCCESS;
451 }
452
453 #undef INIT_SURFACE
454
455 /* ========================================================================= */
456 /* === Private VA/EGL vtable initialization                              === */
457 /* ========================================================================= */
458
459 // Initialize EGL driver context
460 VAStatus va_egl_init_context(VADisplay dpy)
461 {
462     VADisplayContextP pDisplayContext = (VADisplayContextP)dpy;
463     VADriverContextP ctx = pDisplayContext->pDriverContext;
464     VADriverContextEGLP egl_ctx = VA_DRIVER_CONTEXT_EGL(ctx);
465     VADriverVTablePrivEGLP  vtable  = &egl_ctx->vtable;
466
467     if (egl_ctx->is_initialized)
468         return VA_STATUS_SUCCESS;
469
470     if (ctx->vtable_egl && ctx->vtable_egl->vaCreateSurfaceEGL) {
471         vtable->vaQuerySurfaceTargetsEGL = vaQuerySurfaceTargetsEGL_impl_driver;
472         vtable->vaCreateSurfaceEGL = vaCreateSurfaceEGL_impl_driver;
473         vtable->vaDestroySurfaceEGL = vaDestroySurfaceEGL_impl_driver;
474         vtable->vaAssociateSurfaceEGL = vaAssociateSurfaceEGL_impl_driver;
475         vtable->vaSyncSurfaceEGL = vaSyncSurfaceEGL_impl_driver;
476         vtable->vaGetSurfaceInfoEGL = vaGetSurfaceInfoEGL_impl_driver;
477         vtable->vaDeassociateSurfaceEGL = vaDeassociateSurfaceEGL_impl_driver;
478     }
479     else {
480         if (pDisplayContext->vaCreateNativePixmap == NULL ||
481             pDisplayContext->vaFreeNativePixmap == NULL)
482             return VA_STATUS_ERROR_UNIMPLEMENTED;
483
484         if (!check_pixmap_extensions(ctx, egl_ctx->egl_display))
485             return VA_STATUS_ERROR_UNIMPLEMENTED;
486
487         vtable->vaQuerySurfaceTargetsEGL = vaQuerySurfaceTargetsEGL_impl_libva;
488         vtable->vaCreateSurfaceEGL = vaCreateSurfaceEGL_impl_libva;
489         vtable->vaDestroySurfaceEGL = vaDestroySurfaceEGL_impl_libva;
490         vtable->vaAssociateSurfaceEGL = vaAssociateSurfaceEGL_impl_libva;
491         vtable->vaSyncSurfaceEGL = vaSyncSurfaceEGL_impl_libva;
492         vtable->vaGetSurfaceInfoEGL = vaGetSurfaceInfoEGL_impl_libva;
493         vtable->vaDeassociateSurfaceEGL = vaDeassociateSurfaceEGL_impl_libva;
494     }
495
496     egl_ctx->is_initialized = 1;
497
498     return VA_STATUS_SUCCESS;
499 }