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