output.c revision abf31e3822665b6bdf5ac78b757a21522c9448b1
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 "vdpau_private.h"
37
38/**
39 * Create a VdpOutputSurface.
40 */
41VdpStatus
42vlVdpOutputSurfaceCreate(VdpDevice device,
43                         VdpRGBAFormat rgba_format,
44                         uint32_t width, uint32_t height,
45                         VdpOutputSurface  *surface)
46{
47   struct pipe_context *pipe;
48   struct pipe_resource res_tmpl, *res;
49   struct pipe_sampler_view sv_templ;
50   struct pipe_surface surf_templ;
51
52   vlVdpOutputSurface *vlsurface = NULL;
53
54   if (!(width && height))
55      return VDP_STATUS_INVALID_SIZE;
56
57   vlVdpDevice *dev = vlGetDataHTAB(device);
58   if (!dev)
59      return VDP_STATUS_INVALID_HANDLE;
60
61   pipe = dev->context;
62   if (!pipe)
63      return VDP_STATUS_INVALID_HANDLE;
64
65   vlsurface = CALLOC(1, sizeof(vlVdpOutputSurface));
66   if (!vlsurface)
67      return VDP_STATUS_RESOURCES;
68
69   vlsurface->device = dev;
70
71   memset(&res_tmpl, 0, sizeof(res_tmpl));
72
73   res_tmpl.target = PIPE_TEXTURE_2D;
74   res_tmpl.format = FormatRGBAToPipe(rgba_format);
75   res_tmpl.width0 = width;
76   res_tmpl.height0 = height;
77   res_tmpl.depth0 = 1;
78   res_tmpl.array_size = 1;
79   res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
80   res_tmpl.usage = PIPE_USAGE_STATIC;
81
82   res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
83   if (!res) {
84      FREE(dev);
85      return VDP_STATUS_ERROR;
86   }
87
88   memset(&sv_templ, 0, sizeof(sv_templ));
89   u_sampler_view_default_template(&sv_templ, res, res->format);
90   vlsurface->sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ);
91   if (!vlsurface->sampler_view) {
92      pipe_resource_reference(&res, NULL);
93      FREE(dev);
94      return VDP_STATUS_ERROR;
95   }
96
97   memset(&surf_templ, 0, sizeof(surf_templ));
98   surf_templ.format = res->format;
99   surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
100   vlsurface->surface = pipe->create_surface(pipe, res, &surf_templ);
101   if (!vlsurface->surface) {
102      pipe_resource_reference(&res, NULL);
103      FREE(dev);
104      return VDP_STATUS_ERROR;
105   }
106
107   *surface = vlAddDataHTAB(vlsurface);
108   if (*surface == 0) {
109      pipe_resource_reference(&res, NULL);
110      FREE(dev);
111      return VDP_STATUS_ERROR;
112   }
113
114   pipe_resource_reference(&res, NULL);
115
116   vl_compositor_init_state(&vlsurface->cstate, pipe);
117   vl_compositor_reset_dirty_area(&vlsurface->dirty_area);
118
119   return VDP_STATUS_OK;
120}
121
122/**
123 * Destroy a VdpOutputSurface.
124 */
125VdpStatus
126vlVdpOutputSurfaceDestroy(VdpOutputSurface surface)
127{
128   vlVdpOutputSurface *vlsurface;
129
130   vlsurface = vlGetDataHTAB(surface);
131   if (!vlsurface)
132      return VDP_STATUS_INVALID_HANDLE;
133
134   vlVdpResolveDelayedRendering(vlsurface->device, NULL, NULL);
135
136   pipe_surface_reference(&vlsurface->surface, NULL);
137   pipe_sampler_view_reference(&vlsurface->sampler_view, NULL);
138   vl_compositor_cleanup_state(&vlsurface->cstate);
139
140   vlRemoveDataHTAB(surface);
141   FREE(vlsurface);
142
143   return VDP_STATUS_OK;
144}
145
146/**
147 * Retrieve the parameters used to create a VdpOutputSurface.
148 */
149VdpStatus
150vlVdpOutputSurfaceGetParameters(VdpOutputSurface surface,
151                                VdpRGBAFormat *rgba_format,
152                                uint32_t *width, uint32_t *height)
153{
154   vlVdpOutputSurface *vlsurface;
155
156   vlsurface = vlGetDataHTAB(surface);
157   if (!vlsurface)
158      return VDP_STATUS_INVALID_HANDLE;
159
160   *rgba_format = PipeToFormatRGBA(vlsurface->sampler_view->texture->format);
161   *width = vlsurface->sampler_view->texture->width0;
162   *height = vlsurface->sampler_view->texture->height0;
163
164   return VDP_STATUS_OK;
165}
166
167/**
168 * Copy image data from a VdpOutputSurface to application memory in the
169 * surface's native format.
170 */
171VdpStatus
172vlVdpOutputSurfaceGetBitsNative(VdpOutputSurface surface,
173                                VdpRect const *source_rect,
174                                void *const *destination_data,
175                                uint32_t const *destination_pitches)
176{
177   return VDP_STATUS_NO_IMPLEMENTATION;
178}
179
180/**
181 * Copy image data from application memory in the surface's native format to
182 * a VdpOutputSurface.
183 */
184VdpStatus
185vlVdpOutputSurfacePutBitsNative(VdpOutputSurface surface,
186                                void const *const *source_data,
187                                uint32_t const *source_pitches,
188                                VdpRect const *destination_rect)
189{
190   return VDP_STATUS_NO_IMPLEMENTATION;
191}
192
193/**
194 * Copy image data from application memory in a specific indexed format to
195 * a VdpOutputSurface.
196 */
197VdpStatus
198vlVdpOutputSurfacePutBitsIndexed(VdpOutputSurface surface,
199                                 VdpIndexedFormat source_indexed_format,
200                                 void const *const *source_data,
201                                 uint32_t const *source_pitch,
202                                 VdpRect const *destination_rect,
203                                 VdpColorTableFormat color_table_format,
204                                 void const *color_table)
205{
206   vlVdpOutputSurface *vlsurface;
207   struct pipe_context *context;
208   struct vl_compositor *compositor;
209   struct vl_compositor_state *cstate;
210
211   enum pipe_format index_format;
212   enum pipe_format colortbl_format;
213
214   struct pipe_resource *res, res_tmpl;
215   struct pipe_sampler_view sv_tmpl;
216   struct pipe_sampler_view *sv_idx = NULL, *sv_tbl = NULL;
217
218   struct pipe_box box;
219   struct u_rect dst_rect;
220
221   vlsurface = vlGetDataHTAB(surface);
222   if (!vlsurface)
223      return VDP_STATUS_INVALID_HANDLE;
224
225   vlVdpResolveDelayedRendering(vlsurface->device, NULL, NULL);
226
227   context = vlsurface->device->context;
228   compositor = &vlsurface->device->compositor;
229   cstate = &vlsurface->cstate;
230
231   index_format = FormatIndexedToPipe(source_indexed_format);
232   if (index_format == PIPE_FORMAT_NONE)
233       return VDP_STATUS_INVALID_INDEXED_FORMAT;
234
235   if (!source_data || !source_pitch)
236       return VDP_STATUS_INVALID_POINTER;
237
238   colortbl_format = FormatColorTableToPipe(color_table_format);
239   if (colortbl_format == PIPE_FORMAT_NONE)
240       return VDP_STATUS_INVALID_COLOR_TABLE_FORMAT;
241
242   if (!color_table)
243       return VDP_STATUS_INVALID_POINTER;
244
245   memset(&res_tmpl, 0, sizeof(res_tmpl));
246   res_tmpl.target = PIPE_TEXTURE_2D;
247   res_tmpl.format = index_format;
248
249   if (destination_rect) {
250      res_tmpl.width0 = abs(destination_rect->x0-destination_rect->x1);
251      res_tmpl.height0 = abs(destination_rect->y0-destination_rect->y1);
252   } else {
253      res_tmpl.width0 = vlsurface->surface->texture->width0;
254      res_tmpl.height0 = vlsurface->surface->texture->height0;
255   }
256   res_tmpl.depth0 = 1;
257   res_tmpl.array_size = 1;
258   res_tmpl.usage = PIPE_USAGE_STAGING;
259   res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
260
261   res = context->screen->resource_create(context->screen, &res_tmpl);
262   if (!res)
263      goto error_resource;
264
265   box.x = box.y = box.z = 0;
266   box.width = res->width0;
267   box.height = res->height0;
268   box.depth = res->depth0;
269
270   context->transfer_inline_write(context, res, 0, PIPE_TRANSFER_WRITE, &box,
271                                  source_data[0], source_pitch[0],
272                                  source_pitch[0] * res->height0);
273
274   memset(&sv_tmpl, 0, sizeof(sv_tmpl));
275   u_sampler_view_default_template(&sv_tmpl, res, res->format);
276
277   sv_idx = context->create_sampler_view(context, res, &sv_tmpl);
278   pipe_resource_reference(&res, NULL);
279
280   if (!sv_idx)
281      goto error_resource;
282
283   memset(&res_tmpl, 0, sizeof(res_tmpl));
284   res_tmpl.target = PIPE_TEXTURE_1D;
285   res_tmpl.format = colortbl_format;
286   res_tmpl.width0 = 1 << util_format_get_component_bits(
287      index_format, UTIL_FORMAT_COLORSPACE_RGB, 0);
288   res_tmpl.height0 = 1;
289   res_tmpl.depth0 = 1;
290   res_tmpl.array_size = 1;
291   res_tmpl.usage = PIPE_USAGE_STAGING;
292   res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
293
294   res = context->screen->resource_create(context->screen, &res_tmpl);
295   if (!res)
296      goto error_resource;
297
298   box.x = box.y = box.z = 0;
299   box.width = res->width0;
300   box.height = res->height0;
301   box.depth = res->depth0;
302
303   context->transfer_inline_write(context, res, 0, PIPE_TRANSFER_WRITE, &box, color_table,
304                                  util_format_get_stride(colortbl_format, res->width0), 0);
305
306   memset(&sv_tmpl, 0, sizeof(sv_tmpl));
307   u_sampler_view_default_template(&sv_tmpl, res, res->format);
308
309   sv_tbl = context->create_sampler_view(context, res, &sv_tmpl);
310   pipe_resource_reference(&res, NULL);
311
312   if (!sv_tbl)
313      goto error_resource;
314
315   vl_compositor_clear_layers(cstate);
316   vl_compositor_set_palette_layer(cstate, compositor, 0, sv_idx, sv_tbl, NULL, NULL, false);
317   vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
318   vl_compositor_render(cstate, compositor, vlsurface->surface, NULL);
319
320   pipe_sampler_view_reference(&sv_idx, NULL);
321   pipe_sampler_view_reference(&sv_tbl, NULL);
322
323   return VDP_STATUS_OK;
324
325error_resource:
326   pipe_sampler_view_reference(&sv_idx, NULL);
327   pipe_sampler_view_reference(&sv_tbl, NULL);
328   return VDP_STATUS_RESOURCES;
329}
330
331/**
332 * Copy image data from application memory in a specific YCbCr format to
333 * a VdpOutputSurface.
334 */
335VdpStatus
336vlVdpOutputSurfacePutBitsYCbCr(VdpOutputSurface surface,
337                               VdpYCbCrFormat source_ycbcr_format,
338                               void const *const *source_data,
339                               uint32_t const *source_pitches,
340                               VdpRect const *destination_rect,
341                               VdpCSCMatrix const *csc_matrix)
342{
343   return VDP_STATUS_NO_IMPLEMENTATION;
344}
345
346static unsigned
347BlendFactorToPipe(VdpOutputSurfaceRenderBlendFactor factor)
348{
349   switch (factor) {
350   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO:
351      return PIPE_BLENDFACTOR_ZERO;
352   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE:
353      return PIPE_BLENDFACTOR_ONE;
354   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_COLOR:
355      return PIPE_BLENDFACTOR_SRC_COLOR;
356   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
357      return PIPE_BLENDFACTOR_INV_SRC_COLOR;
358   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA:
359      return PIPE_BLENDFACTOR_SRC_ALPHA;
360   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
361      return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
362   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_DST_ALPHA:
363      return PIPE_BLENDFACTOR_DST_ALPHA;
364   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
365      return PIPE_BLENDFACTOR_INV_DST_ALPHA;
366   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_DST_COLOR:
367      return PIPE_BLENDFACTOR_DST_COLOR;
368   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
369      return PIPE_BLENDFACTOR_INV_DST_COLOR;
370   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA_SATURATE:
371      return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
372   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_CONSTANT_COLOR:
373      return PIPE_BLENDFACTOR_CONST_COLOR;
374   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
375      return PIPE_BLENDFACTOR_INV_CONST_COLOR;
376   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_CONSTANT_ALPHA:
377      return PIPE_BLENDFACTOR_CONST_ALPHA;
378   case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
379      return PIPE_BLENDFACTOR_INV_CONST_ALPHA;
380   default:
381      assert(0);
382      return PIPE_BLENDFACTOR_ONE;
383   }
384}
385
386static unsigned
387BlendEquationToPipe(VdpOutputSurfaceRenderBlendEquation equation)
388{
389   switch (equation) {
390   case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_SUBTRACT:
391      return PIPE_BLEND_SUBTRACT;
392   case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_REVERSE_SUBTRACT:
393      return PIPE_BLEND_REVERSE_SUBTRACT;
394   case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD:
395      return PIPE_BLEND_ADD;
396   case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_MIN:
397      return PIPE_BLEND_MIN;
398   case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_MAX:
399      return PIPE_BLEND_MAX;
400   default:
401      assert(0);
402      return PIPE_BLEND_ADD;
403   }
404}
405
406static void *
407BlenderToPipe(struct pipe_context *context,
408              VdpOutputSurfaceRenderBlendState const *blend_state)
409{
410   struct pipe_blend_state blend;
411
412   memset(&blend, 0, sizeof blend);
413   blend.independent_blend_enable = 0;
414
415   if (blend_state) {
416      blend.rt[0].blend_enable = 1;
417      blend.rt[0].rgb_src_factor = BlendFactorToPipe(blend_state->blend_factor_source_color);
418      blend.rt[0].rgb_dst_factor = BlendFactorToPipe(blend_state->blend_factor_destination_color);
419      blend.rt[0].alpha_src_factor = BlendFactorToPipe(blend_state->blend_factor_source_alpha);
420      blend.rt[0].alpha_dst_factor = BlendFactorToPipe(blend_state->blend_factor_destination_alpha);
421      blend.rt[0].rgb_func = BlendEquationToPipe(blend_state->blend_equation_color);
422      blend.rt[0].alpha_func = BlendEquationToPipe(blend_state->blend_equation_alpha);
423   } else {
424      blend.rt[0].blend_enable = 0;
425   }
426
427   blend.logicop_enable = 0;
428   blend.logicop_func = PIPE_LOGICOP_CLEAR;
429   blend.rt[0].colormask = PIPE_MASK_RGBA;
430   blend.dither = 0;
431
432   return context->create_blend_state(context, &blend);
433}
434
435/**
436 * Composite a sub-rectangle of a VdpOutputSurface into a sub-rectangle of
437 * another VdpOutputSurface; Output Surface object VdpOutputSurface.
438 */
439VdpStatus
440vlVdpOutputSurfaceRenderOutputSurface(VdpOutputSurface destination_surface,
441                                      VdpRect const *destination_rect,
442                                      VdpOutputSurface source_surface,
443                                      VdpRect const *source_rect,
444                                      VdpColor const *colors,
445                                      VdpOutputSurfaceRenderBlendState const *blend_state,
446                                      uint32_t flags)
447{
448   vlVdpOutputSurface *dst_vlsurface;
449   vlVdpOutputSurface *src_vlsurface;
450
451   struct pipe_context *context;
452   struct vl_compositor *compositor;
453   struct vl_compositor_state *cstate;
454
455   struct u_rect src_rect, dst_rect;
456
457   void *blend;
458
459   dst_vlsurface = vlGetDataHTAB(destination_surface);
460   if (!dst_vlsurface)
461      return VDP_STATUS_INVALID_HANDLE;
462
463   src_vlsurface = vlGetDataHTAB(source_surface);
464   if (!src_vlsurface)
465      return VDP_STATUS_INVALID_HANDLE;
466
467   if (dst_vlsurface->device != src_vlsurface->device)
468      return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
469
470   vlVdpResolveDelayedRendering(dst_vlsurface->device, NULL, NULL);
471
472   context = dst_vlsurface->device->context;
473   compositor = &dst_vlsurface->device->compositor;
474   cstate = &dst_vlsurface->cstate;
475
476   blend = BlenderToPipe(context, blend_state);
477
478   vl_compositor_clear_layers(cstate);
479   vl_compositor_set_layer_blend(cstate, 0, blend, false);
480   vl_compositor_set_rgba_layer(cstate, compositor, 0, src_vlsurface->sampler_view,
481                                RectToPipe(source_rect, &src_rect), NULL, NULL);
482   vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
483   vl_compositor_render(cstate, compositor, dst_vlsurface->surface, NULL);
484
485   context->delete_blend_state(context, blend);
486
487   return VDP_STATUS_OK;
488}
489
490/**
491 * Composite a sub-rectangle of a VdpBitmapSurface into a sub-rectangle of
492 * a VdpOutputSurface; Output Surface object VdpOutputSurface.
493 */
494VdpStatus
495vlVdpOutputSurfaceRenderBitmapSurface(VdpOutputSurface destination_surface,
496                                      VdpRect const *destination_rect,
497                                      VdpBitmapSurface source_surface,
498                                      VdpRect const *source_rect,
499                                      VdpColor const *colors,
500                                      VdpOutputSurfaceRenderBlendState const *blend_state,
501                                      uint32_t flags)
502{
503   vlVdpOutputSurface *dst_vlsurface;
504   vlVdpBitmapSurface *src_vlsurface;
505
506   struct pipe_context *context;
507   struct vl_compositor *compositor;
508   struct vl_compositor_state *cstate;
509
510   struct u_rect src_rect, dst_rect;
511
512   void *blend;
513
514   dst_vlsurface = vlGetDataHTAB(destination_surface);
515   if (!dst_vlsurface)
516      return VDP_STATUS_INVALID_HANDLE;
517
518   src_vlsurface = vlGetDataHTAB(source_surface);
519   if (!src_vlsurface)
520      return VDP_STATUS_INVALID_HANDLE;
521
522   if (dst_vlsurface->device != src_vlsurface->device)
523      return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
524
525   vlVdpResolveDelayedRendering(dst_vlsurface->device, NULL, NULL);
526
527   context = dst_vlsurface->device->context;
528   compositor = &dst_vlsurface->device->compositor;
529   cstate = &dst_vlsurface->cstate;
530
531   blend = BlenderToPipe(context, blend_state);
532
533   vl_compositor_clear_layers(cstate);
534   vl_compositor_set_layer_blend(cstate, 0, blend, false);
535   vl_compositor_set_rgba_layer(cstate, compositor, 0, src_vlsurface->sampler_view,
536                                RectToPipe(source_rect, &src_rect), NULL, NULL);
537   vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
538   vl_compositor_render(cstate, compositor, dst_vlsurface->surface, NULL);
539
540   context->delete_blend_state(context, blend);
541
542   return VDP_STATUS_OK;
543}
544