• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /**************************************************************************
2   *
3   * Copyright 2011 Christian König.
4   * All Rights Reserved.
5   *
6   * Permission is hereby granted, free of charge, to any person obtaining a
7   * copy of this software and associated documentation files (the
8   * "Software"), to deal in the Software without restriction, including
9   * without limitation the rights to use, copy, modify, merge, publish,
10   * distribute, sub license, and/or sell copies of the Software, and to
11   * permit persons to whom the Software is furnished to do so, subject to
12   * the following conditions:
13   *
14   * The above copyright notice and this permission notice (including the
15   * next paragraph) shall be included in all copies or substantial portions
16   * of the Software.
17   *
18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19   * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21   * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22   * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23   * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24   * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25   *
26   **************************************************************************/
27  
28  #include <assert.h>
29  
30  #include "pipe/p_screen.h"
31  #include "pipe/p_context.h"
32  #include "pipe/p_state.h"
33  
34  #include "util/u_format.h"
35  #include "util/u_inlines.h"
36  #include "util/u_sampler.h"
37  #include "util/u_memory.h"
38  
39  #include "vl_video_buffer.h"
40  
41  const enum pipe_format const_resource_formats_YV12[3] = {
42     PIPE_FORMAT_R8_UNORM,
43     PIPE_FORMAT_R8_UNORM,
44     PIPE_FORMAT_R8_UNORM
45  };
46  
47  const enum pipe_format const_resource_formats_NV12[3] = {
48     PIPE_FORMAT_R8_UNORM,
49     PIPE_FORMAT_R8G8_UNORM,
50     PIPE_FORMAT_NONE
51  };
52  
53  const enum pipe_format const_resource_formats_YUVA[3] = {
54     PIPE_FORMAT_R8G8B8A8_UNORM,
55     PIPE_FORMAT_NONE,
56     PIPE_FORMAT_NONE
57  };
58  
59  const enum pipe_format const_resource_formats_VUYA[3] = {
60     PIPE_FORMAT_B8G8R8A8_UNORM,
61     PIPE_FORMAT_NONE,
62     PIPE_FORMAT_NONE
63  };
64  
65  const enum pipe_format const_resource_formats_YUYV[3] = {
66     PIPE_FORMAT_R8G8_R8B8_UNORM,
67     PIPE_FORMAT_NONE,
68     PIPE_FORMAT_NONE
69  };
70  
71  const enum pipe_format const_resource_formats_UYVY[3] = {
72     PIPE_FORMAT_G8R8_B8R8_UNORM,
73     PIPE_FORMAT_NONE,
74     PIPE_FORMAT_NONE
75  };
76  
77  const unsigned const_resource_plane_order_YUV[3] = {
78     0,
79     1,
80     2
81  };
82  
83  const unsigned const_resource_plane_order_YVU[3] = {
84     0,
85     2,
86     1
87  };
88  
89  const enum pipe_format *
vl_video_buffer_formats(struct pipe_screen * screen,enum pipe_format format)90  vl_video_buffer_formats(struct pipe_screen *screen, enum pipe_format format)
91  {
92     switch(format) {
93     case PIPE_FORMAT_YV12:
94        return const_resource_formats_YV12;
95  
96     case PIPE_FORMAT_NV12:
97        return const_resource_formats_NV12;
98  
99     case PIPE_FORMAT_R8G8B8A8_UNORM:
100        return const_resource_formats_YUVA;
101  
102     case PIPE_FORMAT_B8G8R8A8_UNORM:
103        return const_resource_formats_VUYA;
104  
105     case PIPE_FORMAT_YUYV:
106        return const_resource_formats_YUYV;
107  
108     case PIPE_FORMAT_UYVY:
109        return const_resource_formats_UYVY;
110  
111     default:
112        return NULL;
113     }
114  }
115  
116  const unsigned *
vl_video_buffer_plane_order(enum pipe_format format)117  vl_video_buffer_plane_order(enum pipe_format format)
118  {
119     switch(format) {
120     case PIPE_FORMAT_YV12:
121        return const_resource_plane_order_YVU;
122  
123     case PIPE_FORMAT_NV12:
124     case PIPE_FORMAT_R8G8B8A8_UNORM:
125     case PIPE_FORMAT_B8G8R8A8_UNORM:
126     case PIPE_FORMAT_YUYV:
127     case PIPE_FORMAT_UYVY:
128        return const_resource_plane_order_YUV;
129  
130     default:
131        return NULL;
132     }
133  }
134  
135  static enum pipe_format
vl_video_buffer_surface_format(enum pipe_format format)136  vl_video_buffer_surface_format(enum pipe_format format)
137  {
138     const struct util_format_description *desc = util_format_description(format);
139  
140     /* a subsampled formats can't work as surface use RGBA instead */
141     if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
142        return PIPE_FORMAT_R8G8B8A8_UNORM;
143  
144     return format;
145  }
146  
147  boolean
vl_video_buffer_is_format_supported(struct pipe_screen * screen,enum pipe_format format,enum pipe_video_profile profile)148  vl_video_buffer_is_format_supported(struct pipe_screen *screen,
149                                      enum pipe_format format,
150                                      enum pipe_video_profile profile)
151  {
152     const enum pipe_format *resource_formats;
153     unsigned i;
154  
155     resource_formats = vl_video_buffer_formats(screen, format);
156     if (!resource_formats)
157        return false;
158  
159     for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
160        enum pipe_format format = resource_formats[i];
161  
162        if (format == PIPE_FORMAT_NONE)
163           continue;
164  
165        /* we at least need to sample from it */
166        if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW))
167           return false;
168  
169        format = vl_video_buffer_surface_format(format);
170        if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET))
171           return false;
172     }
173  
174     return true;
175  }
176  
177  unsigned
vl_video_buffer_max_size(struct pipe_screen * screen)178  vl_video_buffer_max_size(struct pipe_screen *screen)
179  {
180     uint32_t max_2d_texture_level;
181  
182     max_2d_texture_level = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
183  
184     return 1 << (max_2d_texture_level-1);
185  }
186  
187  void
vl_video_buffer_set_associated_data(struct pipe_video_buffer * vbuf,struct pipe_video_decoder * vdec,void * associated_data,void (* destroy_associated_data)(void *))188  vl_video_buffer_set_associated_data(struct pipe_video_buffer *vbuf,
189                                      struct pipe_video_decoder *vdec,
190                                      void *associated_data,
191                                      void (*destroy_associated_data)(void *))
192  {
193     vbuf->decoder = vdec;
194  
195     if (vbuf->associated_data == associated_data)
196        return;
197  
198     if (vbuf->associated_data)
199        vbuf->destroy_associated_data(vbuf->associated_data);
200  
201     vbuf->associated_data = associated_data;
202     vbuf->destroy_associated_data = destroy_associated_data;
203  }
204  
205  void *
vl_video_buffer_get_associated_data(struct pipe_video_buffer * vbuf,struct pipe_video_decoder * vdec)206  vl_video_buffer_get_associated_data(struct pipe_video_buffer *vbuf,
207                                      struct pipe_video_decoder *vdec)
208  {
209     if (vbuf->decoder == vdec)
210        return vbuf->associated_data;
211     else
212        return NULL;
213  }
214  
215  void
vl_vide_buffer_template(struct pipe_resource * templ,const struct pipe_video_buffer * tmpl,enum pipe_format resource_format,unsigned depth,unsigned usage,unsigned plane)216  vl_vide_buffer_template(struct pipe_resource *templ,
217                          const struct pipe_video_buffer *tmpl,
218                          enum pipe_format resource_format,
219                          unsigned depth, unsigned usage, unsigned plane)
220  {
221     memset(templ, 0, sizeof(*templ));
222     templ->target = depth > 1 ? PIPE_TEXTURE_3D : PIPE_TEXTURE_2D;
223     templ->format = resource_format;
224     templ->width0 = tmpl->width;
225     templ->height0 = tmpl->height;
226     templ->depth0 = depth;
227     templ->array_size = 1;
228     templ->bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
229     templ->usage = usage;
230  
231     if (plane > 0) {
232        if (tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
233           templ->width0 /= 2;
234           templ->height0 /= 2;
235        } else if (tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) {
236           templ->height0 /= 2;
237        }
238     }
239  }
240  
241  static void
vl_video_buffer_destroy(struct pipe_video_buffer * buffer)242  vl_video_buffer_destroy(struct pipe_video_buffer *buffer)
243  {
244     struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
245     unsigned i;
246  
247     assert(buf);
248  
249     for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
250        pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
251        pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
252        pipe_resource_reference(&buf->resources[i], NULL);
253     }
254  
255     for (i = 0; i < VL_NUM_COMPONENTS * 2; ++i)
256        pipe_surface_reference(&buf->surfaces[i], NULL);
257  
258     vl_video_buffer_set_associated_data(buffer, NULL, NULL, NULL);
259  
260     FREE(buffer);
261  }
262  
263  static struct pipe_sampler_view **
vl_video_buffer_sampler_view_planes(struct pipe_video_buffer * buffer)264  vl_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)
265  {
266     struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
267     struct pipe_sampler_view sv_templ;
268     struct pipe_context *pipe;
269     unsigned i;
270  
271     assert(buf);
272  
273     pipe = buf->base.context;
274  
275     for (i = 0; i < buf->num_planes; ++i ) {
276        if (!buf->sampler_view_planes[i]) {
277           memset(&sv_templ, 0, sizeof(sv_templ));
278           u_sampler_view_default_template(&sv_templ, buf->resources[i], buf->resources[i]->format);
279  
280           if (util_format_get_nr_components(buf->resources[i]->format) == 1)
281              sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = sv_templ.swizzle_a = PIPE_SWIZZLE_RED;
282  
283           buf->sampler_view_planes[i] = pipe->create_sampler_view(pipe, buf->resources[i], &sv_templ);
284           if (!buf->sampler_view_planes[i])
285              goto error;
286        }
287     }
288  
289     return buf->sampler_view_planes;
290  
291  error:
292     for (i = 0; i < buf->num_planes; ++i )
293        pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
294  
295     return NULL;
296  }
297  
298  static struct pipe_sampler_view **
vl_video_buffer_sampler_view_components(struct pipe_video_buffer * buffer)299  vl_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)
300  {
301     struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
302     struct pipe_sampler_view sv_templ;
303     struct pipe_context *pipe;
304     const enum pipe_format *sampler_format;
305     const unsigned *plane_order;
306     unsigned i, j, component;
307  
308     assert(buf);
309  
310     pipe = buf->base.context;
311  
312     sampler_format = vl_video_buffer_formats(pipe->screen, buf->base.buffer_format);
313     plane_order = vl_video_buffer_plane_order(buf->base.buffer_format);
314  
315     for (component = 0, i = 0; i < buf->num_planes; ++i ) {
316        struct pipe_resource *res = buf->resources[plane_order[i]];
317        const struct util_format_description *desc = util_format_description(res->format);
318        unsigned nr_components = util_format_get_nr_components(res->format);
319        if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
320           nr_components = 3;
321  
322        for (j = 0; j < nr_components && component < VL_NUM_COMPONENTS; ++j, ++component) {
323           if (buf->sampler_view_components[component])
324              continue;
325  
326           memset(&sv_templ, 0, sizeof(sv_templ));
327           u_sampler_view_default_template(&sv_templ, res, sampler_format[plane_order[i]]);
328           sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_RED + j;
329           sv_templ.swizzle_a = PIPE_SWIZZLE_ONE;
330           buf->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ);
331           if (!buf->sampler_view_components[component])
332              goto error;
333        }
334     }
335     assert(component == VL_NUM_COMPONENTS);
336  
337     return buf->sampler_view_components;
338  
339  error:
340     for (i = 0; i < VL_NUM_COMPONENTS; ++i )
341        pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
342  
343     return NULL;
344  }
345  
346  static struct pipe_surface **
vl_video_buffer_surfaces(struct pipe_video_buffer * buffer)347  vl_video_buffer_surfaces(struct pipe_video_buffer *buffer)
348  {
349     struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
350     struct pipe_surface surf_templ;
351     struct pipe_context *pipe;
352     unsigned i, j, depth, surf;
353  
354     assert(buf);
355  
356     pipe = buf->base.context;
357  
358     depth = buffer->interlaced ? 2 : 1;
359     for (i = 0, surf = 0; i < depth; ++i ) {
360        for (j = 0; j < VL_NUM_COMPONENTS; ++j, ++surf) {
361           assert(surf < (VL_NUM_COMPONENTS * 2));
362  
363           if (!buf->resources[j]) {
364              pipe_surface_reference(&buf->surfaces[surf], NULL);
365              continue;
366           }
367  
368           if (!buf->surfaces[surf]) {
369              memset(&surf_templ, 0, sizeof(surf_templ));
370              surf_templ.format = vl_video_buffer_surface_format(buf->resources[j]->format);
371              surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
372              surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = i;
373              buf->surfaces[surf] = pipe->create_surface(pipe, buf->resources[j], &surf_templ);
374              if (!buf->surfaces[surf])
375                 goto error;
376           }
377        }
378     }
379  
380     return buf->surfaces;
381  
382  error:
383     for (i = 0; i < (VL_NUM_COMPONENTS * 2); ++i )
384        pipe_surface_reference(&buf->surfaces[i], NULL);
385  
386     return NULL;
387  }
388  
389  struct pipe_video_buffer *
vl_video_buffer_create(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl)390  vl_video_buffer_create(struct pipe_context *pipe,
391                         const struct pipe_video_buffer *tmpl)
392  {
393     const enum pipe_format *resource_formats;
394     struct pipe_video_buffer templat, *result;
395     bool pot_buffers;
396  
397     assert(pipe);
398     assert(tmpl->width > 0 && tmpl->height > 0);
399  
400     pot_buffers = !pipe->screen->get_video_param
401     (
402        pipe->screen,
403        PIPE_VIDEO_PROFILE_UNKNOWN,
404        PIPE_VIDEO_CAP_NPOT_TEXTURES
405     );
406  
407     resource_formats = vl_video_buffer_formats(pipe->screen, tmpl->buffer_format);
408     if (!resource_formats)
409        return NULL;
410  
411     templat = *tmpl;
412     templat.width = pot_buffers ? util_next_power_of_two(tmpl->width)
413                   : align(tmpl->width, VL_MACROBLOCK_WIDTH);
414     templat.height = pot_buffers ? util_next_power_of_two(tmpl->height)
415                    : align(tmpl->height, VL_MACROBLOCK_HEIGHT);
416  
417     if (tmpl->interlaced)
418        templat.height /= 2;
419  
420     result = vl_video_buffer_create_ex
421     (
422        pipe, &templat, resource_formats,
423        tmpl->interlaced ? 2 : 1, PIPE_USAGE_STATIC
424     );
425  
426  
427     if (result && tmpl->interlaced)
428        result->height *= 2;
429  
430     return result;
431  }
432  
433  struct pipe_video_buffer *
vl_video_buffer_create_ex(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl,const enum pipe_format resource_formats[VL_NUM_COMPONENTS],unsigned depth,unsigned usage)434  vl_video_buffer_create_ex(struct pipe_context *pipe,
435                            const struct pipe_video_buffer *tmpl,
436                            const enum pipe_format resource_formats[VL_NUM_COMPONENTS],
437                            unsigned depth, unsigned usage)
438  {
439     struct pipe_resource res_tmpl;
440     struct pipe_resource *resources[VL_NUM_COMPONENTS];
441     unsigned i;
442  
443     assert(pipe);
444  
445     memset(resources, 0, sizeof resources);
446  
447     vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[0], depth, usage, 0);
448     resources[0] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
449     if (!resources[0])
450        goto error;
451  
452     if (resource_formats[1] == PIPE_FORMAT_NONE) {
453        assert(resource_formats[2] == PIPE_FORMAT_NONE);
454        return vl_video_buffer_create_ex2(pipe, tmpl, resources);
455     }
456  
457     vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[1], depth, usage, 1);
458     resources[1] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
459     if (!resources[1])
460        goto error;
461  
462     if (resource_formats[2] == PIPE_FORMAT_NONE)
463        return vl_video_buffer_create_ex2(pipe, tmpl, resources);
464  
465     vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[2], depth, usage, 2);
466     resources[2] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
467     if (!resources[2])
468        goto error;
469  
470     return vl_video_buffer_create_ex2(pipe, tmpl, resources);
471  
472  error:
473     for (i = 0; i < VL_NUM_COMPONENTS; ++i)
474        pipe_resource_reference(&resources[i], NULL);
475  
476     return NULL;
477  }
478  
479  struct pipe_video_buffer *
vl_video_buffer_create_ex2(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl,struct pipe_resource * resources[VL_NUM_COMPONENTS])480  vl_video_buffer_create_ex2(struct pipe_context *pipe,
481                             const struct pipe_video_buffer *tmpl,
482                             struct pipe_resource *resources[VL_NUM_COMPONENTS])
483  {
484     struct vl_video_buffer *buffer;
485     unsigned i;
486  
487     buffer = CALLOC_STRUCT(vl_video_buffer);
488  
489     buffer->base = *tmpl;
490     buffer->base.context = pipe;
491     buffer->base.destroy = vl_video_buffer_destroy;
492     buffer->base.get_sampler_view_planes = vl_video_buffer_sampler_view_planes;
493     buffer->base.get_sampler_view_components = vl_video_buffer_sampler_view_components;
494     buffer->base.get_surfaces = vl_video_buffer_surfaces;
495     buffer->num_planes = 0;
496  
497     for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
498        buffer->resources[i] = resources[i];
499        if (resources[i])
500           buffer->num_planes++;
501     }
502  
503     return &buffer->base;
504  }
505