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 */
43VdpStatus
44vlVdpOutputSurfaceCreate(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 */
132VdpStatus
133vlVdpOutputSurfaceDestroy(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 */
162VdpStatus
163vlVdpOutputSurfaceGetParameters(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 */
184VdpStatus
185vlVdpOutputSurfaceGetBitsNative(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 */
237VdpStatus
238vlVdpOutputSurfacePutBitsNative(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 */
271VdpStatus
272vlVdpOutputSurfacePutBitsIndexed(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
401error_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 */
412VdpStatus
413vlVdpOutputSurfacePutBitsYCbCr(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
507static unsigned
508BlendFactorToPipe(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
547static unsigned
548BlendEquationToPipe(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
567static void *
568BlenderToPipe(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
596static struct vertex4f *
597ColorsToPipe(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 */
622VdpStatus
623vlVdpOutputSurfaceRenderOutputSurface(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 */
681VdpStatus
682vlVdpOutputSurfaceRenderBitmapSurface(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