• Home
  • 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 VMWARE 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/format/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 unsigned const_resource_plane_order_YUV[3] = {
42    0,
43    1,
44    2
45 };
46 
47 const unsigned const_resource_plane_order_YVU[3] = {
48    0,
49    2,
50    1
51 };
52 
53 void
vl_get_video_buffer_formats(struct pipe_screen * screen,enum pipe_format format,enum pipe_format out_format[VL_NUM_COMPONENTS])54 vl_get_video_buffer_formats(struct pipe_screen *screen, enum pipe_format format,
55                             enum pipe_format out_format[VL_NUM_COMPONENTS])
56 {
57    unsigned num_planes = util_format_get_num_planes(format);
58    unsigned i;
59 
60    for (i = 0; i < num_planes; i++)
61       out_format[i] = util_format_get_plane_format(format, i);
62    for (; i < VL_NUM_COMPONENTS; i++)
63       out_format[i] = PIPE_FORMAT_NONE;
64 
65    if (format == PIPE_FORMAT_YUYV)
66       out_format[0] = PIPE_FORMAT_R8G8_R8B8_UNORM;
67    else if (format == PIPE_FORMAT_UYVY)
68       out_format[0] = PIPE_FORMAT_G8R8_B8R8_UNORM;
69 }
70 
71 const unsigned *
vl_video_buffer_plane_order(enum pipe_format format)72 vl_video_buffer_plane_order(enum pipe_format format)
73 {
74    switch(format) {
75    case PIPE_FORMAT_YV12:
76    case PIPE_FORMAT_IYUV:
77       return const_resource_plane_order_YVU;
78 
79    case PIPE_FORMAT_NV12:
80    case PIPE_FORMAT_NV21:
81    case PIPE_FORMAT_Y8_U8_V8_444_UNORM:
82    case PIPE_FORMAT_R8G8B8A8_UNORM:
83    case PIPE_FORMAT_R8G8B8X8_UNORM:
84    case PIPE_FORMAT_B8G8R8A8_UNORM:
85    case PIPE_FORMAT_B8G8R8X8_UNORM:
86    case PIPE_FORMAT_YUYV:
87    case PIPE_FORMAT_UYVY:
88    case PIPE_FORMAT_P010:
89    case PIPE_FORMAT_P016:
90       return const_resource_plane_order_YUV;
91 
92    default:
93       return NULL;
94    }
95 }
96 
97 static enum pipe_format
vl_video_buffer_surface_format(enum pipe_format format)98 vl_video_buffer_surface_format(enum pipe_format format)
99 {
100    const struct util_format_description *desc = util_format_description(format);
101 
102    /* a subsampled formats can't work as surface use RGBA instead */
103    if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
104       return PIPE_FORMAT_R8G8B8A8_UNORM;
105 
106    return format;
107 }
108 
109 bool
vl_video_buffer_is_format_supported(struct pipe_screen * screen,enum pipe_format format,enum pipe_video_profile profile,enum pipe_video_entrypoint entrypoint)110 vl_video_buffer_is_format_supported(struct pipe_screen *screen,
111                                     enum pipe_format format,
112                                     enum pipe_video_profile profile,
113                                     enum pipe_video_entrypoint entrypoint)
114 {
115    enum pipe_format resource_formats[VL_NUM_COMPONENTS];
116    unsigned i;
117 
118    vl_get_video_buffer_formats(screen, format, resource_formats);
119 
120    for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
121       enum pipe_format fmt = resource_formats[i];
122 
123       if (fmt == PIPE_FORMAT_NONE)
124          continue;
125 
126       /* we at least need to sample from it */
127       if (!screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D, 0, 0, PIPE_BIND_SAMPLER_VIEW))
128          continue;
129 
130       fmt = vl_video_buffer_surface_format(fmt);
131       if (screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D, 0, 0, PIPE_BIND_RENDER_TARGET))
132          return true;
133    }
134 
135    return false;
136 }
137 
138 unsigned
vl_video_buffer_max_size(struct pipe_screen * screen)139 vl_video_buffer_max_size(struct pipe_screen *screen)
140 {
141    return screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_SIZE);
142 }
143 
144 void
vl_video_buffer_set_associated_data(struct pipe_video_buffer * vbuf,struct pipe_video_codec * vcodec,void * associated_data,void (* destroy_associated_data)(void *))145 vl_video_buffer_set_associated_data(struct pipe_video_buffer *vbuf,
146                                     struct pipe_video_codec *vcodec,
147                                     void *associated_data,
148                                     void (*destroy_associated_data)(void *))
149 {
150    vbuf->codec = vcodec;
151 
152    if (vbuf->associated_data == associated_data)
153       return;
154 
155    if (vbuf->associated_data)
156       vbuf->destroy_associated_data(vbuf->associated_data);
157 
158    vbuf->associated_data = associated_data;
159    vbuf->destroy_associated_data = destroy_associated_data;
160 }
161 
162 void *
vl_video_buffer_get_associated_data(struct pipe_video_buffer * vbuf,struct pipe_video_codec * vcodec)163 vl_video_buffer_get_associated_data(struct pipe_video_buffer *vbuf,
164                                     struct pipe_video_codec *vcodec)
165 {
166    if (vbuf->codec == vcodec)
167       return vbuf->associated_data;
168    else
169       return NULL;
170 }
171 
172 void
vl_video_buffer_template(struct pipe_resource * templ,const struct pipe_video_buffer * tmpl,enum pipe_format resource_format,unsigned depth,unsigned array_size,unsigned usage,unsigned plane,enum pipe_video_chroma_format chroma_format)173 vl_video_buffer_template(struct pipe_resource *templ,
174                          const struct pipe_video_buffer *tmpl,
175                          enum pipe_format resource_format,
176                          unsigned depth, unsigned array_size,
177                          unsigned usage, unsigned plane,
178                          enum pipe_video_chroma_format chroma_format)
179 {
180    unsigned height = tmpl->height;
181 
182    memset(templ, 0, sizeof(*templ));
183    if (depth > 1)
184       templ->target = PIPE_TEXTURE_3D;
185    else if (array_size > 1)
186       templ->target = PIPE_TEXTURE_2D_ARRAY;
187    else
188       templ->target = PIPE_TEXTURE_2D;
189    templ->format = resource_format;
190    templ->width0 = tmpl->width;
191    templ->depth0 = depth;
192    templ->array_size = array_size;
193    templ->bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET | tmpl->bind;
194    templ->usage = usage;
195 
196    vl_video_buffer_adjust_size(&templ->width0, &height, plane,
197                                chroma_format, false);
198    templ->height0 = height;
199 }
200 
201 void
vl_video_buffer_destroy(struct pipe_video_buffer * buffer)202 vl_video_buffer_destroy(struct pipe_video_buffer *buffer)
203 {
204    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
205    unsigned i;
206 
207    assert(buf);
208 
209    for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
210       pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
211       pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
212       pipe_resource_reference(&buf->resources[i], NULL);
213    }
214 
215    for (i = 0; i < VL_MAX_SURFACES; ++i)
216       pipe_surface_reference(&buf->surfaces[i], NULL);
217 
218    vl_video_buffer_set_associated_data(buffer, NULL, NULL, NULL);
219 
220    FREE(buffer);
221 }
222 
223 static void
vl_video_buffer_resources(struct pipe_video_buffer * buffer,struct pipe_resource ** resources)224 vl_video_buffer_resources(struct pipe_video_buffer *buffer,
225                           struct pipe_resource **resources)
226 {
227    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
228    unsigned num_planes = util_format_get_num_planes(buffer->buffer_format);
229    unsigned i;
230 
231    assert(buf);
232 
233    for (i = 0; i < num_planes; ++i) {
234       resources[i] = buf->resources[i];
235    }
236 }
237 
238 static struct pipe_sampler_view **
vl_video_buffer_sampler_view_planes(struct pipe_video_buffer * buffer)239 vl_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)
240 {
241    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
242    unsigned num_planes = util_format_get_num_planes(buffer->buffer_format);
243    struct pipe_sampler_view sv_templ;
244    struct pipe_context *pipe;
245    unsigned i;
246 
247    assert(buf);
248 
249    pipe = buf->base.context;
250 
251    for (i = 0; i < num_planes; ++i ) {
252       if (!buf->sampler_view_planes[i]) {
253          memset(&sv_templ, 0, sizeof(sv_templ));
254          u_sampler_view_default_template(&sv_templ, buf->resources[i], buf->resources[i]->format);
255 
256          if (util_format_get_nr_components(buf->resources[i]->format) == 1)
257             sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = sv_templ.swizzle_a = PIPE_SWIZZLE_X;
258 
259          buf->sampler_view_planes[i] = pipe->create_sampler_view(pipe, buf->resources[i], &sv_templ);
260          if (!buf->sampler_view_planes[i])
261             goto error;
262       }
263    }
264 
265    return buf->sampler_view_planes;
266 
267 error:
268    for (i = 0; i < num_planes; ++i )
269       pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
270 
271    return NULL;
272 }
273 
274 static struct pipe_sampler_view **
vl_video_buffer_sampler_view_components(struct pipe_video_buffer * buffer)275 vl_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)
276 {
277    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
278    struct pipe_sampler_view sv_templ;
279    struct pipe_context *pipe;
280    enum pipe_format sampler_format[VL_NUM_COMPONENTS];
281    const unsigned *plane_order;
282    unsigned i, j, component;
283 
284    assert(buf);
285 
286    pipe = buf->base.context;
287 
288    vl_get_video_buffer_formats(pipe->screen, buf->base.buffer_format, sampler_format);
289    plane_order = vl_video_buffer_plane_order(buf->base.buffer_format);
290 
291    for (component = 0, i = 0; i < buf->num_planes; ++i ) {
292       struct pipe_resource *res = buf->resources[plane_order[i]];
293       const struct util_format_description *desc = util_format_description(res->format);
294       unsigned nr_components = util_format_get_nr_components(res->format);
295       if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
296          nr_components = 3;
297 
298       for (j = 0; j < nr_components && component < VL_NUM_COMPONENTS; ++j, ++component) {
299          unsigned pipe_swizzle;
300 
301          if (buf->sampler_view_components[component])
302             continue;
303 
304          memset(&sv_templ, 0, sizeof(sv_templ));
305          u_sampler_view_default_template(&sv_templ, res, sampler_format[plane_order[i]]);
306          pipe_swizzle = (buf->base.buffer_format == PIPE_FORMAT_YUYV || buf->base.buffer_format == PIPE_FORMAT_UYVY) ?
307                         (PIPE_SWIZZLE_X + j + 1) % 3 :
308                         (PIPE_SWIZZLE_X + j);
309          sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = pipe_swizzle;
310          sv_templ.swizzle_a = PIPE_SWIZZLE_1;
311 
312          buf->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ);
313          if (!buf->sampler_view_components[component])
314             goto error;
315       }
316    }
317    assert(component == VL_NUM_COMPONENTS);
318 
319    return buf->sampler_view_components;
320 
321 error:
322    for (i = 0; i < VL_NUM_COMPONENTS; ++i )
323       pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
324 
325    return NULL;
326 }
327 
328 static struct pipe_surface **
vl_video_buffer_surfaces(struct pipe_video_buffer * buffer)329 vl_video_buffer_surfaces(struct pipe_video_buffer *buffer)
330 {
331    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
332    struct pipe_surface surf_templ;
333    struct pipe_context *pipe;
334    unsigned i, j, array_size, surf;
335 
336    assert(buf);
337 
338    pipe = buf->base.context;
339 
340    array_size = buffer->interlaced ? 2 : 1;
341    for (i = 0, surf = 0; i < VL_NUM_COMPONENTS; ++i) {
342       for (j = 0; j < array_size; ++j, ++surf) {
343          assert(surf < VL_MAX_SURFACES);
344 
345          if (!buf->resources[i]) {
346             pipe_surface_reference(&buf->surfaces[surf], NULL);
347             continue;
348          }
349 
350          if (!buf->surfaces[surf]) {
351             memset(&surf_templ, 0, sizeof(surf_templ));
352             surf_templ.format = vl_video_buffer_surface_format(buf->resources[i]->format);
353             surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = j;
354             buf->surfaces[surf] = pipe->create_surface(pipe, buf->resources[i], &surf_templ);
355             if (!buf->surfaces[surf])
356                goto error;
357          }
358       }
359    }
360 
361    return buf->surfaces;
362 
363 error:
364    for (i = 0; i < VL_MAX_SURFACES; ++i )
365       pipe_surface_reference(&buf->surfaces[i], NULL);
366 
367    return NULL;
368 }
369 
370 struct pipe_video_buffer *
vl_video_buffer_create(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl)371 vl_video_buffer_create(struct pipe_context *pipe,
372                        const struct pipe_video_buffer *tmpl)
373 {
374    enum pipe_format resource_formats[VL_NUM_COMPONENTS];
375    struct pipe_video_buffer templat, *result;
376    bool pot_buffers;
377 
378    assert(pipe);
379    assert(tmpl->width > 0 && tmpl->height > 0);
380 
381    pot_buffers = !pipe->screen->get_video_param
382    (
383       pipe->screen,
384       PIPE_VIDEO_PROFILE_UNKNOWN,
385       PIPE_VIDEO_ENTRYPOINT_UNKNOWN,
386       PIPE_VIDEO_CAP_NPOT_TEXTURES
387    );
388 
389    vl_get_video_buffer_formats(pipe->screen, tmpl->buffer_format, resource_formats);
390 
391    templat = *tmpl;
392    templat.width = pot_buffers ? util_next_power_of_two(tmpl->width)
393                  : align(tmpl->width, VL_MACROBLOCK_WIDTH);
394    templat.height = pot_buffers ? util_next_power_of_two(tmpl->height)
395                   : align(tmpl->height, VL_MACROBLOCK_HEIGHT);
396 
397    if (tmpl->interlaced)
398       templat.height /= 2;
399 
400    result = vl_video_buffer_create_ex
401    (
402       pipe, &templat, resource_formats,
403       1, tmpl->interlaced ? 2 : 1, PIPE_USAGE_DEFAULT,
404       pipe_format_to_chroma_format(templat.buffer_format)
405    );
406 
407 
408    if (result && tmpl->interlaced)
409       result->height *= 2;
410 
411    return result;
412 }
413 
414 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 array_size,unsigned usage,enum pipe_video_chroma_format chroma_format)415 vl_video_buffer_create_ex(struct pipe_context *pipe,
416                           const struct pipe_video_buffer *tmpl,
417                           const enum pipe_format resource_formats[VL_NUM_COMPONENTS],
418                           unsigned depth, unsigned array_size, unsigned usage,
419                           enum pipe_video_chroma_format chroma_format)
420 {
421    struct pipe_resource res_tmpl;
422    struct pipe_resource *resources[VL_NUM_COMPONENTS];
423    unsigned i;
424 
425    assert(pipe);
426 
427    memset(resources, 0, sizeof resources);
428 
429    vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[0], depth, array_size,
430                             usage, 0, chroma_format);
431    resources[0] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
432    if (!resources[0])
433       goto error;
434 
435    if (resource_formats[1] == PIPE_FORMAT_NONE) {
436       assert(resource_formats[2] == PIPE_FORMAT_NONE);
437       return vl_video_buffer_create_ex2(pipe, tmpl, resources);
438    }
439 
440    vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[1], depth, array_size,
441                             usage, 1, chroma_format);
442    resources[1] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
443    if (!resources[1])
444       goto error;
445 
446    if (resource_formats[2] == PIPE_FORMAT_NONE)
447       return vl_video_buffer_create_ex2(pipe, tmpl, resources);
448 
449    vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[2], depth, array_size,
450                             usage, 2, chroma_format);
451    resources[2] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
452    if (!resources[2])
453       goto error;
454 
455    return vl_video_buffer_create_ex2(pipe, tmpl, resources);
456 
457 error:
458    for (i = 0; i < VL_NUM_COMPONENTS; ++i)
459       pipe_resource_reference(&resources[i], NULL);
460 
461    return NULL;
462 }
463 
464 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])465 vl_video_buffer_create_ex2(struct pipe_context *pipe,
466                            const struct pipe_video_buffer *tmpl,
467                            struct pipe_resource *resources[VL_NUM_COMPONENTS])
468 {
469    struct vl_video_buffer *buffer;
470    unsigned i;
471 
472    buffer = CALLOC_STRUCT(vl_video_buffer);
473    if (!buffer)
474       return NULL;
475 
476    buffer->base = *tmpl;
477    buffer->base.context = pipe;
478    buffer->base.destroy = vl_video_buffer_destroy;
479    buffer->base.get_resources = vl_video_buffer_resources;
480    buffer->base.get_sampler_view_planes = vl_video_buffer_sampler_view_planes;
481    buffer->base.get_sampler_view_components = vl_video_buffer_sampler_view_components;
482    buffer->base.get_surfaces = vl_video_buffer_surfaces;
483    buffer->num_planes = 0;
484 
485    for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
486       buffer->resources[i] = resources[i];
487       if (resources[i])
488          buffer->num_planes++;
489    }
490 
491    return &buffer->base;
492 }
493 
494 /* Create pipe_video_buffer by using resource_create with planar formats. */
495 struct pipe_video_buffer *
vl_video_buffer_create_as_resource(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl,const uint64_t * modifiers,int modifiers_count)496 vl_video_buffer_create_as_resource(struct pipe_context *pipe,
497                                    const struct pipe_video_buffer *tmpl,
498                                    const uint64_t *modifiers,
499                                    int modifiers_count)
500 {
501    struct pipe_resource templ, *resources[VL_NUM_COMPONENTS] = {0};
502    unsigned array_size =  tmpl->interlaced ? 2 : 1;
503 
504    memset(&templ, 0, sizeof(templ));
505    templ.target = array_size > 1 ? PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D;
506    templ.width0 = align(tmpl->width, VL_MACROBLOCK_WIDTH);
507    templ.height0 = align(tmpl->height / array_size, VL_MACROBLOCK_HEIGHT);
508    templ.depth0 = 1;
509    templ.array_size = array_size;
510    templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET | tmpl->bind;
511    templ.usage = PIPE_USAGE_DEFAULT;
512 
513    if (tmpl->buffer_format == PIPE_FORMAT_YUYV)
514       templ.format = PIPE_FORMAT_R8G8_R8B8_UNORM;
515    else if (tmpl->buffer_format == PIPE_FORMAT_UYVY)
516       templ.format = PIPE_FORMAT_G8R8_B8R8_UNORM;
517    else
518       templ.format = tmpl->buffer_format;
519 
520    if (modifiers)
521       resources[0] = pipe->screen->resource_create_with_modifiers(pipe->screen,
522                                                                   &templ, modifiers,
523                                                                   modifiers_count);
524    else
525       resources[0] = pipe->screen->resource_create(pipe->screen, &templ);
526    if (!resources[0])
527       return NULL;
528 
529    if (resources[0]->next) {
530       pipe_resource_reference(&resources[1], resources[0]->next);
531       if (resources[1]->next)
532          pipe_resource_reference(&resources[2], resources[1]->next);
533    }
534 
535    struct pipe_video_buffer vidtemplate = *tmpl;
536    vidtemplate.width = templ.width0;
537    vidtemplate.height = templ.height0 * array_size;
538    return vl_video_buffer_create_ex2(pipe, &vidtemplate, resources);
539 }
540