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