1 /*
2  *  vdpau_subpic.c - VDPAU backend for VA-API (VA subpictures)
3  *
4  *  libva-vdpau-driver (C) 2009-2011 Splitted-Desktop Systems
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
19  */
20 
21 #include "sysdeps.h"
22 #include "vdpau_subpic.h"
23 #include "vdpau_video.h"
24 #include "vdpau_image.h"
25 #include "vdpau_buffer.h"
26 #include "utils.h"
27 
28 #define DEBUG 1
29 #include "debug.h"
30 
31 
32 // List of supported subpicture formats
33 typedef struct {
34     VdpImageFormatType  vdp_format_type;
35     uint32_t            vdp_format;
36     VAImageFormat       va_format;
37     unsigned int        va_flags;
38 } vdpau_subpic_format_map_t;
39 
40 static const vdpau_subpic_format_map_t
41 vdpau_subpic_formats_map[VDPAU_MAX_SUBPICTURE_FORMATS + 1] = {
42     { VDP_IMAGE_FORMAT_TYPE_INDEXED, VDP_INDEXED_FORMAT_A4I4,
43       { VA_FOURCC('A','I','4','4'), VA_MSB_FIRST, 8, },
44       0 },
45     { VDP_IMAGE_FORMAT_TYPE_INDEXED, VDP_INDEXED_FORMAT_I4A4,
46       { VA_FOURCC('I','A','4','4'), VA_MSB_FIRST, 8, },
47       0 },
48     { VDP_IMAGE_FORMAT_TYPE_INDEXED, VDP_INDEXED_FORMAT_A8I8,
49       { VA_FOURCC('A','I','8','8'), VA_MSB_FIRST, 16, },
50       0 },
51     { VDP_IMAGE_FORMAT_TYPE_INDEXED, VDP_INDEXED_FORMAT_I8A8,
52       { VA_FOURCC('I','A','8','8'), VA_MSB_FIRST, 16, },
53       0 },
54 #ifdef WORDS_BIGENDIAN
55     { VDP_IMAGE_FORMAT_TYPE_RGBA, VDP_RGBA_FORMAT_B8G8R8A8,
56       { VA_FOURCC('A','R','G','B'), VA_MSB_FIRST, 32,
57         32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 },
58       VA_SUBPICTURE_GLOBAL_ALPHA },
59     { VDP_IMAGE_FORMAT_TYPE_RGBA, VDP_RGBA_FORMAT_R8G8B8A8,
60       { VA_FOURCC('A','B','G','R'), VA_MSB_FIRST, 32,
61         32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
62       VA_SUBPICTURE_GLOBAL_ALPHA },
63 #else
64     { VDP_IMAGE_FORMAT_TYPE_RGBA, VDP_RGBA_FORMAT_B8G8R8A8,
65       { VA_FOURCC('B','G','R','A'), VA_LSB_FIRST, 32,
66         32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 },
67       VA_SUBPICTURE_GLOBAL_ALPHA },
68     { VDP_IMAGE_FORMAT_TYPE_RGBA, VDP_RGBA_FORMAT_R8G8B8A8,
69       { VA_FOURCC('R','G','B','A'), VA_LSB_FIRST, 32,
70         32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
71       VA_SUBPICTURE_GLOBAL_ALPHA },
72 #endif
73     { 0, VDP_INVALID_HANDLE, }
74 };
75 
76 // Returns a suitable VDPAU subpicture format for the specified VA image format
get_format(const VAImageFormat * format)77 static const vdpau_subpic_format_map_t *get_format(const VAImageFormat *format)
78 {
79     unsigned int i;
80     for (i = 0; vdpau_subpic_formats_map[i].va_format.fourcc != 0; i++) {
81         const vdpau_subpic_format_map_t * const m = &vdpau_subpic_formats_map[i];
82         if (m->va_format.fourcc == format->fourcc &&
83             (m->vdp_format_type == VDP_IMAGE_FORMAT_TYPE_RGBA ?
84              (m->va_format.byte_order == format->byte_order &&
85               m->va_format.red_mask   == format->red_mask   &&
86               m->va_format.green_mask == format->green_mask &&
87               m->va_format.blue_mask  == format->blue_mask  &&
88               m->va_format.alpha_mask == format->alpha_mask) : 1))
89             return m;
90     }
91     return NULL;
92 }
93 
94 // Checks whether the VDPAU implementation supports the specified image format
95 static inline VdpBool
is_supported_format(vdpau_driver_data_t * driver_data,const vdpau_subpic_format_map_t * format)96 is_supported_format(
97     vdpau_driver_data_t             *driver_data,
98     const vdpau_subpic_format_map_t *format)
99 {
100     VdpBool is_supported = VDP_FALSE;
101     VdpStatus vdp_status;
102     uint32_t max_width, max_height;
103 
104     switch (format->vdp_format_type) {
105     case VDP_IMAGE_FORMAT_TYPE_RGBA:
106         vdp_status = vdpau_bitmap_surface_query_capabilities(
107             driver_data,
108             driver_data->vdp_device,
109             format->vdp_format,
110             &is_supported,
111             &max_width,
112             &max_height
113         );
114         break;
115     case VDP_IMAGE_FORMAT_TYPE_INDEXED:
116         vdp_status = vdpau_output_surface_query_put_bits_indexed_capabilities(
117             driver_data,
118             driver_data->vdp_device,
119             VDP_RGBA_FORMAT_B8G8R8A8,
120             format->vdp_format,
121             VDP_COLOR_TABLE_FORMAT_B8G8R8X8,
122             &is_supported
123         );
124         break;
125     default:
126         vdp_status = VDP_STATUS_ERROR;
127         break;
128     }
129     return vdp_status == VDP_STATUS_OK && is_supported;
130 }
131 
132 // Append association to the subpicture
133 static int
subpicture_add_association(object_subpicture_p obj_subpicture,SubpictureAssociationP assoc)134 subpicture_add_association(
135     object_subpicture_p    obj_subpicture,
136     SubpictureAssociationP assoc
137 )
138 {
139     SubpictureAssociationP *assocs;
140     assocs = realloc_buffer(
141         (void **)&obj_subpicture->assocs,
142         &obj_subpicture->assocs_count_max,
143         1 + obj_subpicture->assocs_count,
144         sizeof(obj_subpicture->assocs[0])
145     );
146     if (!assocs)
147         return -1;
148 
149     assocs[obj_subpicture->assocs_count++] = assoc;
150     return 0;
151 }
152 
153 // Remove association at the specified index from the subpicture
154 static inline int
subpicture_remove_association_at(object_subpicture_p obj_subpicture,int index)155 subpicture_remove_association_at(object_subpicture_p obj_subpicture, int index)
156 {
157     ASSERT(obj_subpicture->assocs && obj_subpicture->assocs_count > 0);
158     if (!obj_subpicture->assocs || obj_subpicture->assocs_count == 0)
159         return -1;
160 
161     /* Replace with the last association */
162     const unsigned int last = obj_subpicture->assocs_count - 1;
163     obj_subpicture->assocs[index] = obj_subpicture->assocs[last];
164     obj_subpicture->assocs[last] = NULL;
165     obj_subpicture->assocs_count--;
166     return 0;
167 }
168 
169 #if 0
170 // Remove association from the subpicture
171 static int
172 subpicture_remove_association(
173     object_subpicture_p    obj_subpicture,
174     SubpictureAssociationP assoc
175 )
176 {
177     ASSERT(obj_subpicture->assocs && obj_subpicture->assocs_count > 0);
178     if (!obj_subpicture->assocs || obj_subpicture->assocs_count == 0)
179         return -1;
180 
181     unsigned int i;
182     for (i = 0; i < obj_subpicture->assocs_count; i++) {
183         if (obj_subpicture->assocs[i] == assoc)
184             return subpicture_remove_association_at(obj_subpicture, i);
185     }
186     return -1;
187 }
188 #endif
189 
190 // Associate one surface to the subpicture
191 VAStatus
subpicture_associate_1(object_subpicture_p obj_subpicture,object_surface_p obj_surface,const VARectangle * src_rect,const VARectangle * dst_rect,unsigned int flags)192 subpicture_associate_1(
193     object_subpicture_p obj_subpicture,
194     object_surface_p    obj_surface,
195     const VARectangle  *src_rect,
196     const VARectangle  *dst_rect,
197     unsigned int        flags
198 )
199 {
200     /* we only support the VA_SUBPICTURE_GLOBAL_ALPHA flag */
201     if (flags & ~VA_SUBPICTURE_GLOBAL_ALPHA)
202         return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
203 
204     SubpictureAssociationP assoc = malloc(sizeof(*assoc));
205     if (!assoc)
206         return VA_STATUS_ERROR_ALLOCATION_FAILED;
207 
208     assoc->subpicture = obj_subpicture->base.id;
209     assoc->surface    = obj_surface->base.id;
210     assoc->src_rect   = *src_rect;
211     assoc->dst_rect   = *dst_rect;
212     assoc->flags      = flags;
213 
214     VAStatus status = surface_add_association(obj_surface, assoc);
215     if (status !=  VA_STATUS_SUCCESS) {
216         free(assoc);
217         return status;
218     }
219 
220     if (subpicture_add_association(obj_subpicture, assoc) < 0) {
221         surface_remove_association(obj_surface, assoc);
222         free(assoc);
223         return VA_STATUS_ERROR_ALLOCATION_FAILED;
224     }
225     return VA_STATUS_SUCCESS;
226 }
227 
228 // Associate surfaces to the subpicture
229 static VAStatus
associate_subpicture(vdpau_driver_data_t * driver_data,object_subpicture_p obj_subpicture,VASurfaceID * surfaces,unsigned int num_surfaces,const VARectangle * src_rect,const VARectangle * dst_rect,unsigned int flags)230 associate_subpicture(
231     vdpau_driver_data_t *driver_data,
232     object_subpicture_p obj_subpicture,
233     VASurfaceID        *surfaces,
234     unsigned int        num_surfaces,
235     const VARectangle  *src_rect,
236     const VARectangle  *dst_rect,
237     unsigned int        flags
238 )
239 {
240     VAStatus status;
241     unsigned int i;
242 
243     for (i = 0; i < num_surfaces; i++) {
244         object_surface_p const obj_surface = VDPAU_SURFACE(surfaces[i]);
245         if (!obj_surface)
246             return VA_STATUS_ERROR_INVALID_SURFACE;
247         status = subpicture_associate_1(obj_subpicture, obj_surface,
248                                         src_rect, dst_rect, flags);
249         if (status != VA_STATUS_SUCCESS)
250             return status;
251     }
252     return VA_STATUS_SUCCESS;
253 }
254 
255 // Deassociate one surface from the subpicture
256 VAStatus
subpicture_deassociate_1(object_subpicture_p obj_subpicture,object_surface_p obj_surface)257 subpicture_deassociate_1(
258     object_subpicture_p obj_subpicture,
259     object_surface_p    obj_surface
260 )
261 {
262     ASSERT(obj_subpicture->assocs && obj_subpicture->assocs_count > 0);
263     if (!obj_subpicture->assocs || obj_subpicture->assocs_count == 0)
264         return VA_STATUS_ERROR_OPERATION_FAILED;
265 
266     unsigned int i;
267     for (i = 0; i < obj_subpicture->assocs_count; i++) {
268         SubpictureAssociationP const assoc = obj_subpicture->assocs[i];
269         ASSERT(assoc);
270         if (assoc && assoc->surface == obj_surface->base.id) {
271             surface_remove_association(obj_surface, assoc);
272             subpicture_remove_association_at(obj_subpicture, i);
273             free(assoc);
274             return VA_STATUS_SUCCESS;
275         }
276     }
277     return VA_STATUS_ERROR_OPERATION_FAILED;
278 }
279 
280 // Deassociate surfaces from the subpicture
281 static VAStatus
deassociate_subpicture(vdpau_driver_data_t * driver_data,object_subpicture_p obj_subpicture,VASurfaceID * surfaces,unsigned int num_surfaces)282 deassociate_subpicture(
283     vdpau_driver_data_t *driver_data,
284     object_subpicture_p obj_subpicture,
285     VASurfaceID        *surfaces,
286     unsigned int        num_surfaces
287 )
288 {
289     VAStatus status, error = VA_STATUS_SUCCESS;
290     unsigned int i;
291 
292     for (i = 0; i < num_surfaces; i++) {
293         object_surface_p const obj_surface = VDPAU_SURFACE(surfaces[i]);
294         if (!obj_surface)
295             return VA_STATUS_ERROR_INVALID_SURFACE;
296         status = subpicture_deassociate_1(obj_subpicture, obj_surface);
297         if (status != VA_STATUS_SUCCESS) {
298             /* Simply report the first error to the user */
299             if (error == VA_STATUS_SUCCESS)
300                 error = status;
301         }
302     }
303     return error;
304 }
305 
306 // Commit subpicture to VDPAU surface
307 VAStatus
commit_subpicture(vdpau_driver_data_p driver_data,object_subpicture_p obj_subpicture)308 commit_subpicture(
309     vdpau_driver_data_p driver_data,
310     object_subpicture_p obj_subpicture
311 )
312 {
313     object_image_p obj_image = VDPAU_IMAGE(obj_subpicture->image_id);
314     if (!obj_image)
315         return VA_STATUS_ERROR_INVALID_IMAGE;
316 
317     ASSERT(obj_subpicture->width == obj_image->image.width);
318     if (obj_subpicture->width != obj_image->image.width)
319         return VA_STATUS_ERROR_OPERATION_FAILED;
320 
321     ASSERT(obj_subpicture->height == obj_image->image.height);
322     if (obj_subpicture->height != obj_image->image.height)
323         return VA_STATUS_ERROR_OPERATION_FAILED;
324 
325     object_buffer_p obj_buffer = VDPAU_BUFFER(obj_image->image.buf);
326     if (!obj_buffer)
327         return VA_STATUS_ERROR_INVALID_BUFFER;
328 
329     /* Update video surface only if the image (hence its buffer) was
330        updated since our last synchronisation.
331 
332        NOTE: this assumes the user really unmaps the buffer when he is
333        done with it, as it is actually required */
334     if (obj_subpicture->last_commit >= obj_buffer->mtime)
335         return VA_STATUS_SUCCESS;
336 
337     VdpRect dirty_rect;
338     dirty_rect.x0 = obj_subpicture->width;
339     dirty_rect.y0 = obj_subpicture->height;
340     dirty_rect.x1 = 0;
341     dirty_rect.y1 = 0;
342 
343     unsigned int i;
344     for (i = 0; i < obj_subpicture->assocs_count; i++) {
345         const VARectangle * const rect = &obj_subpicture->assocs[i]->src_rect;
346         dirty_rect.x0 = MIN(dirty_rect.x0, rect->x);
347         dirty_rect.y0 = MIN(dirty_rect.y0, rect->y);
348         dirty_rect.x1 = MAX(dirty_rect.x1, rect->x + rect->width);
349         dirty_rect.y1 = MAX(dirty_rect.y1, rect->y + rect->height);
350     }
351 
352     const uint8_t *src;
353     uint32_t src_stride;
354     src_stride = obj_image->image.pitches[0];
355     src = ((uint8_t *)obj_buffer->buffer_data + obj_image->image.offsets[0] +
356            dirty_rect.y0 * obj_image->image.pitches[0] +
357            dirty_rect.x0 * ((obj_image->image.format.bits_per_pixel + 7) / 8));
358 
359     VdpStatus vdp_status;
360     switch (obj_subpicture->vdp_format_type) {
361     case VDP_IMAGE_FORMAT_TYPE_RGBA:
362         vdp_status = vdpau_bitmap_surface_put_bits_native(
363             driver_data,
364             obj_subpicture->vdp_bitmap_surface,
365             &src, &src_stride,
366             &dirty_rect
367         );
368         break;
369     case VDP_IMAGE_FORMAT_TYPE_INDEXED:
370         vdp_status = vdpau_output_surface_put_bits_indexed(
371             driver_data,
372             obj_subpicture->vdp_output_surface,
373             obj_subpicture->vdp_format,
374             &src, &src_stride,
375             &dirty_rect,
376             VDP_COLOR_TABLE_FORMAT_B8G8R8X8,
377             obj_image->vdp_palette
378         );
379         break;
380     default:
381         vdp_status = VDP_STATUS_ERROR;
382         break;
383     }
384     if (vdp_status != VDP_STATUS_OK)
385         return vdpau_get_VAStatus(vdp_status);
386 
387     obj_subpicture->last_commit = obj_buffer->mtime;
388     return VA_STATUS_SUCCESS;
389 }
390 
391 // Create subpicture with image
392 static VAStatus
create_subpicture(vdpau_driver_data_t * driver_data,object_image_p obj_image,VASubpictureID * subpicture)393 create_subpicture(
394     vdpau_driver_data_t *driver_data,
395     object_image_p       obj_image,
396     VASubpictureID      *subpicture
397 )
398 {
399     *subpicture = object_heap_allocate(&driver_data->subpicture_heap);
400     if (*subpicture == VA_INVALID_ID)
401         return VA_STATUS_ERROR_ALLOCATION_FAILED;
402 
403     object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(*subpicture);
404     if (!obj_subpicture)
405         return VA_STATUS_ERROR_ALLOCATION_FAILED;
406 
407     const vdpau_subpic_format_map_t *m = get_format(&obj_image->image.format);
408     if (!is_supported_format(driver_data, m))
409         return VA_STATUS_ERROR_UNKNOWN; /* VA_STATUS_ERROR_UNSUPPORTED_FORMAT */
410 
411     obj_subpicture->image_id           = obj_image->base.id;
412     obj_subpicture->assocs             = NULL;
413     obj_subpicture->assocs_count       = 0;
414     obj_subpicture->assocs_count_max   = 0;
415     obj_subpicture->width              = obj_image->image.width;
416     obj_subpicture->height             = obj_image->image.height;
417     obj_subpicture->vdp_bitmap_surface = VDP_INVALID_HANDLE;
418     obj_subpicture->vdp_output_surface = VDP_INVALID_HANDLE;
419     obj_subpicture->last_commit        = 0;
420     obj_subpicture->vdp_format_type    = m->vdp_format_type;
421     obj_subpicture->vdp_format         = m->vdp_format;
422     obj_subpicture->alpha              = 1.0;
423 
424     VdpStatus vdp_status;
425     switch (obj_subpicture->vdp_format_type) {
426     case VDP_IMAGE_FORMAT_TYPE_RGBA:
427         vdp_status = vdpau_bitmap_surface_create(
428             driver_data,
429             driver_data->vdp_device,
430             obj_subpicture->vdp_format,
431             obj_subpicture->width,
432             obj_subpicture->height,
433             VDP_FALSE,
434             &obj_subpicture->vdp_bitmap_surface
435         );
436         break;
437     case VDP_IMAGE_FORMAT_TYPE_INDEXED:
438         vdp_status = vdpau_output_surface_create(
439             driver_data,
440             driver_data->vdp_device,
441             VDP_RGBA_FORMAT_B8G8R8A8,
442             obj_subpicture->width,
443             obj_subpicture->height,
444             &obj_subpicture->vdp_output_surface
445         );
446         break;
447     default:
448         vdp_status = VDP_STATUS_ERROR;
449         break;
450     }
451     return vdpau_get_VAStatus(vdp_status);
452 }
453 
454 // Destroy subpicture
455 static void
destroy_subpicture(vdpau_driver_data_t * driver_data,object_subpicture_p obj_subpicture)456 destroy_subpicture(
457     vdpau_driver_data_t *driver_data,
458     object_subpicture_p obj_subpicture
459 )
460 {
461     object_surface_p obj_surface;
462     VAStatus status;
463     unsigned int i, n;
464 
465     if (obj_subpicture->assocs) {
466         const unsigned int n_assocs = obj_subpicture->assocs_count;
467         for (i = 0, n = 0; i < n_assocs; i++) {
468             SubpictureAssociationP const assoc = obj_subpicture->assocs[0];
469             if (!assoc)
470                 continue;
471             obj_surface = VDPAU_SURFACE(assoc->surface);
472             if (!obj_surface)
473                 continue;
474             status = subpicture_deassociate_1(obj_subpicture, obj_surface);
475             if (status == VA_STATUS_SUCCESS)
476                 ++n;
477         }
478         if (n != n_assocs)
479             vdpau_error_message("vaDestroySubpicture(): subpicture 0x%08x still "
480                                "has %d surfaces associated to it\n",
481                                obj_subpicture->base.id, n_assocs - n);
482         free(obj_subpicture->assocs);
483         obj_subpicture->assocs = NULL;
484     }
485     obj_subpicture->assocs_count = 0;
486     obj_subpicture->assocs_count_max = 0;
487 
488     if (obj_subpicture->vdp_bitmap_surface != VDP_INVALID_HANDLE) {
489         vdpau_bitmap_surface_destroy(
490             driver_data,
491             obj_subpicture->vdp_bitmap_surface
492         );
493         obj_subpicture->vdp_bitmap_surface = VDP_INVALID_HANDLE;
494     }
495 
496     if (obj_subpicture->vdp_output_surface != VDP_INVALID_HANDLE) {
497         vdpau_output_surface_destroy(
498             driver_data,
499             obj_subpicture->vdp_output_surface
500         );
501         obj_subpicture->vdp_output_surface = VDP_INVALID_HANDLE;
502     }
503 
504     obj_subpicture->image_id = VA_INVALID_ID;
505     object_heap_free(&driver_data->subpicture_heap,
506                      (object_base_p)obj_subpicture);
507 }
508 
509 // vaQuerySubpictureFormats
510 VAStatus
vdpau_QuerySubpictureFormats(VADriverContextP ctx,VAImageFormat * format_list,unsigned int * flags,unsigned int * num_formats)511 vdpau_QuerySubpictureFormats(
512     VADriverContextP    ctx,
513     VAImageFormat      *format_list,
514     unsigned int       *flags,
515     unsigned int       *num_formats
516 )
517 {
518     VDPAU_DRIVER_DATA_INIT;
519 
520     int n;
521     for (n = 0; vdpau_subpic_formats_map[n].va_format.fourcc != 0; n++) {
522         const vdpau_subpic_format_map_t * const m = &vdpau_subpic_formats_map[n];
523         if (is_supported_format(driver_data, m)) {
524             if (format_list)
525                 format_list[n] = m->va_format;
526             if (flags)
527                 flags[n] = m->va_flags;
528         }
529     }
530 
531     if (num_formats)
532         *num_formats = n;
533 
534     return VA_STATUS_SUCCESS;
535 }
536 
537 // vaCreateSubpicture
538 VAStatus
vdpau_CreateSubpicture(VADriverContextP ctx,VAImageID image,VASubpictureID * subpicture)539 vdpau_CreateSubpicture(
540     VADriverContextP    ctx,
541     VAImageID           image,
542     VASubpictureID     *subpicture
543 )
544 {
545     VDPAU_DRIVER_DATA_INIT;
546 
547     if (!subpicture)
548         return VA_STATUS_ERROR_INVALID_PARAMETER;
549 
550     object_image_p obj_image = VDPAU_IMAGE(image);
551     if (!obj_image)
552         return VA_STATUS_ERROR_INVALID_IMAGE;
553 
554     return create_subpicture(driver_data, obj_image, subpicture);
555 }
556 
557 // vaDestroySubpicture
558 VAStatus
vdpau_DestroySubpicture(VADriverContextP ctx,VASubpictureID subpicture)559 vdpau_DestroySubpicture(
560     VADriverContextP    ctx,
561     VASubpictureID      subpicture
562 )
563 {
564     VDPAU_DRIVER_DATA_INIT;
565 
566     object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
567     if (!obj_subpicture)
568         return VA_STATUS_ERROR_INVALID_SUBPICTURE;
569 
570     destroy_subpicture(driver_data, obj_subpicture);
571     return VA_STATUS_SUCCESS;
572 }
573 
574 // vaSetSubpictureImage
575 VAStatus
vdpau_SetSubpictureImage(VADriverContextP ctx,VASubpictureID subpicture,VAImageID image)576 vdpau_SetSubpictureImage(
577     VADriverContextP    ctx,
578     VASubpictureID      subpicture,
579     VAImageID           image
580 )
581 {
582     VDPAU_DRIVER_DATA_INIT;
583 
584     object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
585     if (!obj_subpicture)
586         return VA_STATUS_ERROR_INVALID_SUBPICTURE;
587 
588     object_image_p obj_image = VDPAU_IMAGE(image);
589     if (!obj_image)
590         return VA_STATUS_ERROR_INVALID_IMAGE;
591 
592     obj_subpicture->image_id = obj_image->base.id;
593     return VA_STATUS_SUCCESS;
594 }
595 
596 // vaSetSubpicturePalette (not a PUBLIC interface)
597 VAStatus
vdpau_SetSubpicturePalette(VADriverContextP ctx,VASubpictureID subpicture,unsigned char * palette)598 vdpau_SetSubpicturePalette(
599     VADriverContextP    ctx,
600     VASubpictureID      subpicture,
601     unsigned char      *palette
602 )
603 {
604     /* TODO */
605     return VA_STATUS_ERROR_OPERATION_FAILED;
606 }
607 
608 // vaSetSubpictureChromaKey
609 VAStatus
vdpau_SetSubpictureChromakey(VADriverContextP ctx,VASubpictureID subpicture,unsigned int chromakey_min,unsigned int chromakey_max,unsigned int chromakey_mask)610 vdpau_SetSubpictureChromakey(
611     VADriverContextP    ctx,
612     VASubpictureID      subpicture,
613     unsigned int        chromakey_min,
614     unsigned int        chromakey_max,
615     unsigned int        chromakey_mask
616 )
617 {
618     VDPAU_DRIVER_DATA_INIT;
619 
620     object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
621     if (!obj_subpicture)
622         return VA_STATUS_ERROR_INVALID_SUBPICTURE;
623 
624     obj_subpicture->chromakey_min  = chromakey_min;
625     obj_subpicture->chromakey_max  = chromakey_max;
626     obj_subpicture->chromakey_mask = chromakey_mask;
627     return VA_STATUS_SUCCESS;
628 }
629 
630 // vaSetSubpictureGlobalAlpha
631 VAStatus
vdpau_SetSubpictureGlobalAlpha(VADriverContextP ctx,VASubpictureID subpicture,float global_alpha)632 vdpau_SetSubpictureGlobalAlpha(
633     VADriverContextP    ctx,
634     VASubpictureID      subpicture,
635     float               global_alpha
636 )
637 {
638     VDPAU_DRIVER_DATA_INIT;
639 
640     object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
641     if (!obj_subpicture)
642         return VA_STATUS_ERROR_INVALID_SUBPICTURE;
643 
644     obj_subpicture->alpha = global_alpha;
645     return VA_STATUS_SUCCESS;
646 }
647 
648 // vaAssociateSubpicture
649 VAStatus
vdpau_AssociateSubpicture(VADriverContextP ctx,VASubpictureID subpicture,VASurfaceID * target_surfaces,int num_surfaces,short src_x,short src_y,short dest_x,short dest_y,unsigned short width,unsigned short height,unsigned int flags)650 vdpau_AssociateSubpicture(
651     VADriverContextP    ctx,
652     VASubpictureID      subpicture,
653     VASurfaceID        *target_surfaces,
654     int                 num_surfaces,
655     short               src_x,
656     short               src_y,
657     short               dest_x,
658     short               dest_y,
659     unsigned short      width,
660     unsigned short      height,
661     unsigned int        flags
662 )
663 {
664     VDPAU_DRIVER_DATA_INIT;
665 
666     if (!target_surfaces || num_surfaces == 0)
667         return VA_STATUS_SUCCESS;
668 
669     object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
670     if (!obj_subpicture)
671         return VA_STATUS_ERROR_INVALID_SUBPICTURE;
672 
673     VARectangle src_rect, dst_rect;
674     src_rect.x      = src_x;
675     src_rect.y      = src_y;
676     src_rect.width  = width;
677     src_rect.height = height;
678     dst_rect.x      = dest_x;
679     dst_rect.y      = dest_y;
680     dst_rect.width  = width;
681     dst_rect.height = height;
682     return associate_subpicture(driver_data, obj_subpicture,
683                                 target_surfaces, num_surfaces,
684                                 &src_rect, &dst_rect, flags);
685 }
686 
687 // vaAssociateSubpicture2
688 VAStatus
vdpau_AssociateSubpicture_full(VADriverContextP ctx,VASubpictureID subpicture,VASurfaceID * target_surfaces,int num_surfaces,short src_x,short src_y,unsigned short src_width,unsigned short src_height,short dest_x,short dest_y,unsigned short dest_width,unsigned short dest_height,unsigned int flags)689 vdpau_AssociateSubpicture_full(
690     VADriverContextP    ctx,
691     VASubpictureID      subpicture,
692     VASurfaceID        *target_surfaces,
693     int                 num_surfaces,
694     short               src_x,
695     short               src_y,
696     unsigned short      src_width,
697     unsigned short      src_height,
698     short               dest_x,
699     short               dest_y,
700     unsigned short      dest_width,
701     unsigned short      dest_height,
702     unsigned int        flags
703 )
704 {
705     VDPAU_DRIVER_DATA_INIT;
706 
707     if (!target_surfaces || num_surfaces == 0)
708         return VA_STATUS_SUCCESS;
709 
710     object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
711     if (!obj_subpicture)
712         return VA_STATUS_ERROR_INVALID_SUBPICTURE;
713 
714     VARectangle src_rect, dst_rect;
715     src_rect.x      = src_x;
716     src_rect.y      = src_y;
717     src_rect.width  = src_width;
718     src_rect.height = src_height;
719     dst_rect.x      = dest_x;
720     dst_rect.y      = dest_y;
721     dst_rect.width  = dest_width;
722     dst_rect.height = dest_height;
723     return associate_subpicture(driver_data, obj_subpicture,
724                                 target_surfaces, num_surfaces,
725                                 &src_rect, &dst_rect, flags);
726 }
727 
728 // vaDeassociateSubpicture
729 VAStatus
vdpau_DeassociateSubpicture(VADriverContextP ctx,VASubpictureID subpicture,VASurfaceID * target_surfaces,int num_surfaces)730 vdpau_DeassociateSubpicture(
731     VADriverContextP    ctx,
732     VASubpictureID      subpicture,
733     VASurfaceID        *target_surfaces,
734     int                 num_surfaces
735 )
736 {
737     VDPAU_DRIVER_DATA_INIT;
738 
739     if (!target_surfaces || num_surfaces == 0)
740         return VA_STATUS_SUCCESS;
741 
742     object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
743     if (!obj_subpicture)
744         return VA_STATUS_ERROR_INVALID_SUBPICTURE;
745 
746     return deassociate_subpicture(driver_data, obj_subpicture,
747                                   target_surfaces, num_surfaces);
748 }
749