• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2010 Thomas Balling Sørensen.
4  * Copyright 2011 Christian König.
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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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 <vdpau/vdpau.h>
30 
31 #include "util/u_debug.h"
32 #include "util/u_memory.h"
33 #include "util/u_sampler.h"
34 #include "util/u_format.h"
35 
36 #include "vl/vl_csc.h"
37 
38 #include "vdpau_private.h"
39 
40 /**
41  * Create a VdpOutputSurface.
42  */
43 VdpStatus
vlVdpOutputSurfaceCreate(VdpDevice device,VdpRGBAFormat rgba_format,uint32_t width,uint32_t height,VdpOutputSurface * surface)44 vlVdpOutputSurfaceCreate(VdpDevice device,
45                          VdpRGBAFormat rgba_format,
46                          uint32_t width, uint32_t height,
47                          VdpOutputSurface  *surface)
48 {
49    struct pipe_context *pipe;
50    struct pipe_resource res_tmpl, *res;
51    struct pipe_sampler_view sv_templ;
52    struct pipe_surface surf_templ;
53 
54    vlVdpOutputSurface *vlsurface = NULL;
55 
56    if (!(width && height))
57       return VDP_STATUS_INVALID_SIZE;
58 
59    vlVdpDevice *dev = vlGetDataHTAB(device);
60    if (!dev)
61       return VDP_STATUS_INVALID_HANDLE;
62 
63    pipe = dev->context;
64    if (!pipe)
65       return VDP_STATUS_INVALID_HANDLE;
66 
67    vlsurface = CALLOC(1, sizeof(vlVdpOutputSurface));
68    if (!vlsurface)
69       return VDP_STATUS_RESOURCES;
70 
71    vlsurface->device = dev;
72 
73    memset(&res_tmpl, 0, sizeof(res_tmpl));
74 
75    res_tmpl.target = PIPE_TEXTURE_2D;
76    res_tmpl.format = FormatRGBAToPipe(rgba_format);
77    res_tmpl.width0 = width;
78    res_tmpl.height0 = height;
79    res_tmpl.depth0 = 1;
80    res_tmpl.array_size = 1;
81    res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
82    res_tmpl.usage = PIPE_USAGE_STATIC;
83 
84    pipe_mutex_lock(dev->mutex);
85    res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
86    if (!res) {
87       pipe_mutex_unlock(dev->mutex);
88       FREE(dev);
89       return VDP_STATUS_ERROR;
90    }
91 
92    vlVdpDefaultSamplerViewTemplate(&sv_templ, res);
93    vlsurface->sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ);
94    if (!vlsurface->sampler_view) {
95       pipe_resource_reference(&res, NULL);
96       pipe_mutex_unlock(dev->mutex);
97       FREE(dev);
98       return VDP_STATUS_ERROR;
99    }
100 
101    memset(&surf_templ, 0, sizeof(surf_templ));
102    surf_templ.format = res->format;
103    surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
104    vlsurface->surface = pipe->create_surface(pipe, res, &surf_templ);
105    if (!vlsurface->surface) {
106       pipe_resource_reference(&res, NULL);
107       pipe_mutex_unlock(dev->mutex);
108       FREE(dev);
109       return VDP_STATUS_ERROR;
110    }
111 
112    *surface = vlAddDataHTAB(vlsurface);
113    if (*surface == 0) {
114       pipe_resource_reference(&res, NULL);
115       pipe_mutex_unlock(dev->mutex);
116       FREE(dev);
117       return VDP_STATUS_ERROR;
118    }
119 
120    pipe_resource_reference(&res, NULL);
121 
122    vl_compositor_init_state(&vlsurface->cstate, pipe);
123    vl_compositor_reset_dirty_area(&vlsurface->dirty_area);
124    pipe_mutex_unlock(dev->mutex);
125 
126    return VDP_STATUS_OK;
127 }
128 
129 /**
130  * Destroy a VdpOutputSurface.
131  */
132 VdpStatus
vlVdpOutputSurfaceDestroy(VdpOutputSurface surface)133 vlVdpOutputSurfaceDestroy(VdpOutputSurface surface)
134 {
135    vlVdpOutputSurface *vlsurface;
136    struct pipe_context *pipe;
137 
138    vlsurface = vlGetDataHTAB(surface);
139    if (!vlsurface)
140       return VDP_STATUS_INVALID_HANDLE;
141 
142    pipe = vlsurface->device->context;
143 
144    pipe_mutex_lock(vlsurface->device->mutex);
145    vlVdpResolveDelayedRendering(vlsurface->device, NULL, NULL);
146 
147    pipe_surface_reference(&vlsurface->surface, NULL);
148    pipe_sampler_view_reference(&vlsurface->sampler_view, NULL);
149    pipe->screen->fence_reference(pipe->screen, &vlsurface->fence, NULL);
150    vl_compositor_cleanup_state(&vlsurface->cstate);
151    pipe_mutex_unlock(vlsurface->device->mutex);
152 
153    vlRemoveDataHTAB(surface);
154    FREE(vlsurface);
155 
156    return VDP_STATUS_OK;
157 }
158 
159 /**
160  * Retrieve the parameters used to create a VdpOutputSurface.
161  */
162 VdpStatus
vlVdpOutputSurfaceGetParameters(VdpOutputSurface surface,VdpRGBAFormat * rgba_format,uint32_t * width,uint32_t * height)163 vlVdpOutputSurfaceGetParameters(VdpOutputSurface surface,
164                                 VdpRGBAFormat *rgba_format,
165                                 uint32_t *width, uint32_t *height)
166 {
167    vlVdpOutputSurface *vlsurface;
168 
169    vlsurface = vlGetDataHTAB(surface);
170    if (!vlsurface)
171       return VDP_STATUS_INVALID_HANDLE;
172 
173    *rgba_format = PipeToFormatRGBA(vlsurface->sampler_view->texture->format);
174    *width = vlsurface->sampler_view->texture->width0;
175    *height = vlsurface->sampler_view->texture->height0;
176 
177    return VDP_STATUS_OK;
178 }
179 
180 /**
181  * Copy image data from a VdpOutputSurface to application memory in the
182  * surface's native format.
183  */
184 VdpStatus
vlVdpOutputSurfaceGetBitsNative(VdpOutputSurface surface,VdpRect const * source_rect,void * const * destination_data,uint32_t const * destination_pitches)185 vlVdpOutputSurfaceGetBitsNative(VdpOutputSurface surface,
186                                 VdpRect const *source_rect,
187                                 void *const *destination_data,
188                                 uint32_t const *destination_pitches)
189 {
190    vlVdpOutputSurface *vlsurface;
191    struct pipe_context *pipe;
192    struct pipe_resource *res;
193    struct pipe_box box;
194    struct pipe_transfer *transfer;
195    uint8_t *map;
196 
197    vlsurface = vlGetDataHTAB(surface);
198    if (!vlsurface)
199       return VDP_STATUS_INVALID_HANDLE;
200 
201    pipe = vlsurface->device->context;
202    if (!pipe)
203       return VDP_STATUS_INVALID_HANDLE;
204 
205    pipe_mutex_lock(vlsurface->device->mutex);
206    vlVdpResolveDelayedRendering(vlsurface->device, NULL, NULL);
207 
208    res = vlsurface->sampler_view->texture;
209    box = RectToPipeBox(source_rect, res);
210    transfer = pipe->get_transfer(pipe, res, 0, PIPE_TRANSFER_READ, &box);
211    if (transfer == NULL) {
212       pipe_mutex_unlock(vlsurface->device->mutex);
213       return VDP_STATUS_RESOURCES;
214    }
215 
216    map = pipe_transfer_map(pipe, transfer);
217    if (map == NULL) {
218       pipe_transfer_destroy(pipe, transfer);
219       pipe_mutex_unlock(vlsurface->device->mutex);
220       return VDP_STATUS_RESOURCES;
221    }
222 
223    util_copy_rect(*destination_data, res->format, *destination_pitches, 0, 0,
224                   box.width, box.height, map, transfer->stride, 0, 0);
225 
226    pipe_transfer_unmap(pipe, transfer);
227    pipe_transfer_destroy(pipe, transfer);
228    pipe_mutex_unlock(vlsurface->device->mutex);
229 
230    return VDP_STATUS_OK;
231 }
232 
233 /**
234  * Copy image data from application memory in the surface's native format to
235  * a VdpOutputSurface.
236  */
237 VdpStatus
vlVdpOutputSurfacePutBitsNative(VdpOutputSurface surface,void const * const * source_data,uint32_t const * source_pitches,VdpRect const * destination_rect)238 vlVdpOutputSurfacePutBitsNative(VdpOutputSurface surface,
239                                 void const *const *source_data,
240                                 uint32_t const *source_pitches,
241                                 VdpRect const *destination_rect)
242 {
243    vlVdpOutputSurface *vlsurface;
244    struct pipe_box dst_box;
245    struct pipe_context *pipe;
246 
247    vlsurface = vlGetDataHTAB(surface);
248    if (!vlsurface)
249       return VDP_STATUS_INVALID_HANDLE;
250 
251    pipe = vlsurface->device->context;
252    if (!pipe)
253       return VDP_STATUS_INVALID_HANDLE;
254 
255    pipe_mutex_lock(vlsurface->device->mutex);
256    vlVdpResolveDelayedRendering(vlsurface->device, NULL, NULL);
257 
258    dst_box = RectToPipeBox(destination_rect, vlsurface->sampler_view->texture);
259    pipe->transfer_inline_write(pipe, vlsurface->sampler_view->texture, 0,
260                                PIPE_TRANSFER_WRITE, &dst_box, *source_data,
261                                *source_pitches, 0);
262    pipe_mutex_unlock(vlsurface->device->mutex);
263 
264    return VDP_STATUS_OK;
265 }
266 
267 /**
268  * Copy image data from application memory in a specific indexed format to
269  * a VdpOutputSurface.
270  */
271 VdpStatus
vlVdpOutputSurfacePutBitsIndexed(VdpOutputSurface surface,VdpIndexedFormat source_indexed_format,void const * const * source_data,uint32_t const * source_pitch,VdpRect const * destination_rect,VdpColorTableFormat color_table_format,void const * color_table)272 vlVdpOutputSurfacePutBitsIndexed(VdpOutputSurface surface,
273                                  VdpIndexedFormat source_indexed_format,
274                                  void const *const *source_data,
275                                  uint32_t const *source_pitch,
276                                  VdpRect const *destination_rect,
277                                  VdpColorTableFormat color_table_format,
278                                  void const *color_table)
279 {
280    vlVdpOutputSurface *vlsurface;
281    struct pipe_context *context;
282    struct vl_compositor *compositor;
283    struct vl_compositor_state *cstate;
284 
285    enum pipe_format index_format;
286    enum pipe_format colortbl_format;
287 
288    struct pipe_resource *res, res_tmpl;
289    struct pipe_sampler_view sv_tmpl;
290    struct pipe_sampler_view *sv_idx = NULL, *sv_tbl = NULL;
291 
292    struct pipe_box box;
293    struct u_rect dst_rect;
294 
295    vlsurface = vlGetDataHTAB(surface);
296    if (!vlsurface)
297       return VDP_STATUS_INVALID_HANDLE;
298 
299    context = vlsurface->device->context;
300    compositor = &vlsurface->device->compositor;
301    cstate = &vlsurface->cstate;
302 
303    index_format = FormatIndexedToPipe(source_indexed_format);
304    if (index_format == PIPE_FORMAT_NONE)
305        return VDP_STATUS_INVALID_INDEXED_FORMAT;
306 
307    if (!source_data || !source_pitch)
308        return VDP_STATUS_INVALID_POINTER;
309 
310    colortbl_format = FormatColorTableToPipe(color_table_format);
311    if (colortbl_format == PIPE_FORMAT_NONE)
312        return VDP_STATUS_INVALID_COLOR_TABLE_FORMAT;
313 
314    if (!color_table)
315        return VDP_STATUS_INVALID_POINTER;
316 
317    memset(&res_tmpl, 0, sizeof(res_tmpl));
318    res_tmpl.target = PIPE_TEXTURE_2D;
319    res_tmpl.format = index_format;
320 
321    if (destination_rect) {
322       res_tmpl.width0 = abs(destination_rect->x0-destination_rect->x1);
323       res_tmpl.height0 = abs(destination_rect->y0-destination_rect->y1);
324    } else {
325       res_tmpl.width0 = vlsurface->surface->texture->width0;
326       res_tmpl.height0 = vlsurface->surface->texture->height0;
327    }
328    res_tmpl.depth0 = 1;
329    res_tmpl.array_size = 1;
330    res_tmpl.usage = PIPE_USAGE_STAGING;
331    res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
332 
333    pipe_mutex_lock(vlsurface->device->mutex);
334    vlVdpResolveDelayedRendering(vlsurface->device, NULL, NULL);
335 
336    res = context->screen->resource_create(context->screen, &res_tmpl);
337    if (!res)
338       goto error_resource;
339 
340    box.x = box.y = box.z = 0;
341    box.width = res->width0;
342    box.height = res->height0;
343    box.depth = res->depth0;
344 
345    context->transfer_inline_write(context, res, 0, PIPE_TRANSFER_WRITE, &box,
346                                   source_data[0], source_pitch[0],
347                                   source_pitch[0] * res->height0);
348 
349    memset(&sv_tmpl, 0, sizeof(sv_tmpl));
350    u_sampler_view_default_template(&sv_tmpl, res, res->format);
351 
352    sv_idx = context->create_sampler_view(context, res, &sv_tmpl);
353    pipe_resource_reference(&res, NULL);
354 
355    if (!sv_idx)
356       goto error_resource;
357 
358    memset(&res_tmpl, 0, sizeof(res_tmpl));
359    res_tmpl.target = PIPE_TEXTURE_1D;
360    res_tmpl.format = colortbl_format;
361    res_tmpl.width0 = 1 << util_format_get_component_bits(
362       index_format, UTIL_FORMAT_COLORSPACE_RGB, 0);
363    res_tmpl.height0 = 1;
364    res_tmpl.depth0 = 1;
365    res_tmpl.array_size = 1;
366    res_tmpl.usage = PIPE_USAGE_STAGING;
367    res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
368 
369    res = context->screen->resource_create(context->screen, &res_tmpl);
370    if (!res)
371       goto error_resource;
372 
373    box.x = box.y = box.z = 0;
374    box.width = res->width0;
375    box.height = res->height0;
376    box.depth = res->depth0;
377 
378    context->transfer_inline_write(context, res, 0, PIPE_TRANSFER_WRITE, &box, color_table,
379                                   util_format_get_stride(colortbl_format, res->width0), 0);
380 
381    memset(&sv_tmpl, 0, sizeof(sv_tmpl));
382    u_sampler_view_default_template(&sv_tmpl, res, res->format);
383 
384    sv_tbl = context->create_sampler_view(context, res, &sv_tmpl);
385    pipe_resource_reference(&res, NULL);
386 
387    if (!sv_tbl)
388       goto error_resource;
389 
390    vl_compositor_clear_layers(cstate);
391    vl_compositor_set_palette_layer(cstate, compositor, 0, sv_idx, sv_tbl, NULL, NULL, false);
392    vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
393    vl_compositor_render(cstate, compositor, vlsurface->surface, NULL);
394 
395    pipe_sampler_view_reference(&sv_idx, NULL);
396    pipe_sampler_view_reference(&sv_tbl, NULL);
397    pipe_mutex_unlock(vlsurface->device->mutex);
398 
399    return VDP_STATUS_OK;
400 
401 error_resource:
402    pipe_sampler_view_reference(&sv_idx, NULL);
403    pipe_sampler_view_reference(&sv_tbl, NULL);
404    pipe_mutex_unlock(vlsurface->device->mutex);
405    return VDP_STATUS_RESOURCES;
406 }
407 
408 /**
409  * Copy image data from application memory in a specific YCbCr format to
410  * a VdpOutputSurface.
411  */
412 VdpStatus
vlVdpOutputSurfacePutBitsYCbCr(VdpOutputSurface surface,VdpYCbCrFormat source_ycbcr_format,void const * const * source_data,uint32_t const * source_pitches,VdpRect const * destination_rect,VdpCSCMatrix const * csc_matrix)413 vlVdpOutputSurfacePutBitsYCbCr(VdpOutputSurface surface,
414                                VdpYCbCrFormat source_ycbcr_format,
415                                void const *const *source_data,
416                                uint32_t const *source_pitches,
417                                VdpRect const *destination_rect,
418                                VdpCSCMatrix const *csc_matrix)
419 {
420    vlVdpOutputSurface *vlsurface;
421    struct vl_compositor *compositor;
422    struct vl_compositor_state *cstate;
423 
424    struct pipe_context *pipe;
425    enum pipe_format format;
426    struct pipe_video_buffer vtmpl, *vbuffer;
427    struct u_rect dst_rect;
428    struct pipe_sampler_view **sampler_views;
429 
430    unsigned i;
431 
432    vlsurface = vlGetDataHTAB(surface);
433    if (!vlsurface)
434       return VDP_STATUS_INVALID_HANDLE;
435 
436 
437    pipe = vlsurface->device->context;
438    compositor = &vlsurface->device->compositor;
439    cstate = &vlsurface->cstate;
440 
441    format = FormatYCBCRToPipe(source_ycbcr_format);
442    if (format == PIPE_FORMAT_NONE)
443        return VDP_STATUS_INVALID_Y_CB_CR_FORMAT;
444 
445    if (!source_data || !source_pitches)
446        return VDP_STATUS_INVALID_POINTER;
447 
448    pipe_mutex_lock(vlsurface->device->mutex);
449    vlVdpResolveDelayedRendering(vlsurface->device, NULL, NULL);
450    memset(&vtmpl, 0, sizeof(vtmpl));
451    vtmpl.buffer_format = format;
452    vtmpl.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
453 
454    if (destination_rect) {
455       vtmpl.width = abs(destination_rect->x0-destination_rect->x1);
456       vtmpl.height = abs(destination_rect->y0-destination_rect->y1);
457    } else {
458       vtmpl.width = vlsurface->surface->texture->width0;
459       vtmpl.height = vlsurface->surface->texture->height0;
460    }
461 
462    vbuffer = pipe->create_video_buffer(pipe, &vtmpl);
463    if (!vbuffer) {
464       pipe_mutex_unlock(vlsurface->device->mutex);
465       return VDP_STATUS_RESOURCES;
466    }
467 
468    sampler_views = vbuffer->get_sampler_view_planes(vbuffer);
469    if (!sampler_views) {
470       vbuffer->destroy(vbuffer);
471       pipe_mutex_unlock(vlsurface->device->mutex);
472       return VDP_STATUS_RESOURCES;
473    }
474 
475    for (i = 0; i < 3; ++i) {
476       struct pipe_sampler_view *sv = sampler_views[i];
477       if (!sv) continue;
478 
479       struct pipe_box dst_box = {
480          0, 0, 0,
481          sv->texture->width0, sv->texture->height0, 1
482       };
483 
484       pipe->transfer_inline_write(pipe, sv->texture, 0, PIPE_TRANSFER_WRITE, &dst_box,
485                                   source_data[i], source_pitches[i], 0);
486    }
487 
488    if (!csc_matrix) {
489       vl_csc_matrix csc;
490       vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &csc);
491       vl_compositor_set_csc_matrix(cstate, (const vl_csc_matrix*)&csc);
492    } else {
493       vl_compositor_set_csc_matrix(cstate, csc_matrix);
494    }
495 
496    vl_compositor_clear_layers(cstate);
497    vl_compositor_set_buffer_layer(cstate, compositor, 0, vbuffer, NULL, NULL, VL_COMPOSITOR_WEAVE);
498    vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
499    vl_compositor_render(cstate, compositor, vlsurface->surface, NULL);
500 
501    vbuffer->destroy(vbuffer);
502    pipe_mutex_unlock(vlsurface->device->mutex);
503 
504    return VDP_STATUS_OK;
505 }
506 
507 static unsigned
BlendFactorToPipe(VdpOutputSurfaceRenderBlendFactor factor)508 BlendFactorToPipe(VdpOutputSurfaceRenderBlendFactor factor)
509 {
510    switch (factor) {
511    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO:
512       return PIPE_BLENDFACTOR_ZERO;
513    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE:
514       return PIPE_BLENDFACTOR_ONE;
515    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_COLOR:
516       return PIPE_BLENDFACTOR_SRC_COLOR;
517    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
518       return PIPE_BLENDFACTOR_INV_SRC_COLOR;
519    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA:
520       return PIPE_BLENDFACTOR_SRC_ALPHA;
521    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
522       return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
523    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_DST_ALPHA:
524       return PIPE_BLENDFACTOR_DST_ALPHA;
525    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
526       return PIPE_BLENDFACTOR_INV_DST_ALPHA;
527    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_DST_COLOR:
528       return PIPE_BLENDFACTOR_DST_COLOR;
529    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
530       return PIPE_BLENDFACTOR_INV_DST_COLOR;
531    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA_SATURATE:
532       return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
533    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_CONSTANT_COLOR:
534       return PIPE_BLENDFACTOR_CONST_COLOR;
535    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
536       return PIPE_BLENDFACTOR_INV_CONST_COLOR;
537    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_CONSTANT_ALPHA:
538       return PIPE_BLENDFACTOR_CONST_ALPHA;
539    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
540       return PIPE_BLENDFACTOR_INV_CONST_ALPHA;
541    default:
542       assert(0);
543       return PIPE_BLENDFACTOR_ONE;
544    }
545 }
546 
547 static unsigned
BlendEquationToPipe(VdpOutputSurfaceRenderBlendEquation equation)548 BlendEquationToPipe(VdpOutputSurfaceRenderBlendEquation equation)
549 {
550    switch (equation) {
551    case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_SUBTRACT:
552       return PIPE_BLEND_SUBTRACT;
553    case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_REVERSE_SUBTRACT:
554       return PIPE_BLEND_REVERSE_SUBTRACT;
555    case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD:
556       return PIPE_BLEND_ADD;
557    case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_MIN:
558       return PIPE_BLEND_MIN;
559    case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_MAX:
560       return PIPE_BLEND_MAX;
561    default:
562       assert(0);
563       return PIPE_BLEND_ADD;
564    }
565 }
566 
567 static void *
BlenderToPipe(struct pipe_context * context,VdpOutputSurfaceRenderBlendState const * blend_state)568 BlenderToPipe(struct pipe_context *context,
569               VdpOutputSurfaceRenderBlendState const *blend_state)
570 {
571    struct pipe_blend_state blend;
572 
573    memset(&blend, 0, sizeof blend);
574    blend.independent_blend_enable = 0;
575 
576    if (blend_state) {
577       blend.rt[0].blend_enable = 1;
578       blend.rt[0].rgb_src_factor = BlendFactorToPipe(blend_state->blend_factor_source_color);
579       blend.rt[0].rgb_dst_factor = BlendFactorToPipe(blend_state->blend_factor_destination_color);
580       blend.rt[0].alpha_src_factor = BlendFactorToPipe(blend_state->blend_factor_source_alpha);
581       blend.rt[0].alpha_dst_factor = BlendFactorToPipe(blend_state->blend_factor_destination_alpha);
582       blend.rt[0].rgb_func = BlendEquationToPipe(blend_state->blend_equation_color);
583       blend.rt[0].alpha_func = BlendEquationToPipe(blend_state->blend_equation_alpha);
584    } else {
585       blend.rt[0].blend_enable = 0;
586    }
587 
588    blend.logicop_enable = 0;
589    blend.logicop_func = PIPE_LOGICOP_CLEAR;
590    blend.rt[0].colormask = PIPE_MASK_RGBA;
591    blend.dither = 0;
592 
593    return context->create_blend_state(context, &blend);
594 }
595 
596 static struct vertex4f *
ColorsToPipe(VdpColor const * colors,uint32_t flags,struct vertex4f result[4])597 ColorsToPipe(VdpColor const *colors, uint32_t flags, struct vertex4f result[4])
598 {
599    unsigned i;
600    struct vertex4f *dst = result;
601 
602    if (!colors)
603       return NULL;
604 
605    for (i = 0; i < 4; ++i) {
606       dst->x = colors->red;
607       dst->y = colors->green;
608       dst->z = colors->blue;
609       dst->w = colors->alpha;
610 
611       ++dst;
612       if (flags & VDP_OUTPUT_SURFACE_RENDER_COLOR_PER_VERTEX)
613          ++colors;
614    }
615    return result;
616 }
617 
618 /**
619  * Composite a sub-rectangle of a VdpOutputSurface into a sub-rectangle of
620  * another VdpOutputSurface; Output Surface object VdpOutputSurface.
621  */
622 VdpStatus
vlVdpOutputSurfaceRenderOutputSurface(VdpOutputSurface destination_surface,VdpRect const * destination_rect,VdpOutputSurface source_surface,VdpRect const * source_rect,VdpColor const * colors,VdpOutputSurfaceRenderBlendState const * blend_state,uint32_t flags)623 vlVdpOutputSurfaceRenderOutputSurface(VdpOutputSurface destination_surface,
624                                       VdpRect const *destination_rect,
625                                       VdpOutputSurface source_surface,
626                                       VdpRect const *source_rect,
627                                       VdpColor const *colors,
628                                       VdpOutputSurfaceRenderBlendState const *blend_state,
629                                       uint32_t flags)
630 {
631    vlVdpOutputSurface *dst_vlsurface;
632    vlVdpOutputSurface *src_vlsurface;
633 
634    struct pipe_context *context;
635    struct vl_compositor *compositor;
636    struct vl_compositor_state *cstate;
637 
638    struct u_rect src_rect, dst_rect;
639 
640    struct vertex4f vlcolors[4];
641    void *blend;
642 
643    dst_vlsurface = vlGetDataHTAB(destination_surface);
644    if (!dst_vlsurface)
645       return VDP_STATUS_INVALID_HANDLE;
646 
647    src_vlsurface = vlGetDataHTAB(source_surface);
648    if (!src_vlsurface)
649       return VDP_STATUS_INVALID_HANDLE;
650 
651    if (dst_vlsurface->device != src_vlsurface->device)
652       return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
653 
654    pipe_mutex_lock(dst_vlsurface->device->mutex);
655    vlVdpResolveDelayedRendering(dst_vlsurface->device, NULL, NULL);
656 
657    context = dst_vlsurface->device->context;
658    compositor = &dst_vlsurface->device->compositor;
659    cstate = &dst_vlsurface->cstate;
660 
661    blend = BlenderToPipe(context, blend_state);
662 
663    vl_compositor_clear_layers(cstate);
664    vl_compositor_set_layer_blend(cstate, 0, blend, false);
665    vl_compositor_set_rgba_layer(cstate, compositor, 0, src_vlsurface->sampler_view,
666                                 RectToPipe(source_rect, &src_rect), NULL,
667                                 ColorsToPipe(colors, flags, vlcolors));
668    vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
669    vl_compositor_render(cstate, compositor, dst_vlsurface->surface, NULL);
670 
671    context->delete_blend_state(context, blend);
672    pipe_mutex_unlock(dst_vlsurface->device->mutex);
673 
674    return VDP_STATUS_OK;
675 }
676 
677 /**
678  * Composite a sub-rectangle of a VdpBitmapSurface into a sub-rectangle of
679  * a VdpOutputSurface; Output Surface object VdpOutputSurface.
680  */
681 VdpStatus
vlVdpOutputSurfaceRenderBitmapSurface(VdpOutputSurface destination_surface,VdpRect const * destination_rect,VdpBitmapSurface source_surface,VdpRect const * source_rect,VdpColor const * colors,VdpOutputSurfaceRenderBlendState const * blend_state,uint32_t flags)682 vlVdpOutputSurfaceRenderBitmapSurface(VdpOutputSurface destination_surface,
683                                       VdpRect const *destination_rect,
684                                       VdpBitmapSurface source_surface,
685                                       VdpRect const *source_rect,
686                                       VdpColor const *colors,
687                                       VdpOutputSurfaceRenderBlendState const *blend_state,
688                                       uint32_t flags)
689 {
690    vlVdpOutputSurface *dst_vlsurface;
691    vlVdpBitmapSurface *src_vlsurface;
692 
693    struct pipe_context *context;
694    struct vl_compositor *compositor;
695    struct vl_compositor_state *cstate;
696 
697    struct u_rect src_rect, dst_rect;
698 
699    struct vertex4f vlcolors[4];
700    void *blend;
701 
702    dst_vlsurface = vlGetDataHTAB(destination_surface);
703    if (!dst_vlsurface)
704       return VDP_STATUS_INVALID_HANDLE;
705 
706    src_vlsurface = vlGetDataHTAB(source_surface);
707    if (!src_vlsurface)
708       return VDP_STATUS_INVALID_HANDLE;
709 
710    if (dst_vlsurface->device != src_vlsurface->device)
711       return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
712 
713    context = dst_vlsurface->device->context;
714    compositor = &dst_vlsurface->device->compositor;
715    cstate = &dst_vlsurface->cstate;
716 
717    pipe_mutex_lock(dst_vlsurface->device->mutex);
718    vlVdpResolveDelayedRendering(dst_vlsurface->device, NULL, NULL);
719 
720    blend = BlenderToPipe(context, blend_state);
721 
722    vl_compositor_clear_layers(cstate);
723    vl_compositor_set_layer_blend(cstate, 0, blend, false);
724    vl_compositor_set_rgba_layer(cstate, compositor, 0, src_vlsurface->sampler_view,
725                                 RectToPipe(source_rect, &src_rect), NULL,
726                                 ColorsToPipe(colors, flags, vlcolors));
727    vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
728    vl_compositor_render(cstate, compositor, dst_vlsurface->surface, NULL);
729 
730    context->delete_blend_state(context, blend);
731    pipe_mutex_unlock(dst_vlsurface->device->mutex);
732 
733    return VDP_STATUS_OK;
734 }
735