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