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