vl/video_buffer: add YUVA and VUYA support
[mesa.git] / src / gallium / auxiliary / vl / vl_video_buffer.c
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 unsigned const_resource_plane_order_YUV[3] = {
66 0,
67 1,
68 2
69 };
70
71 const unsigned const_resource_plane_order_YVU[3] = {
72 0,
73 2,
74 1
75 };
76
77 const enum pipe_format *
78 vl_video_buffer_formats(struct pipe_screen *screen, enum pipe_format format)
79 {
80 switch(format) {
81 case PIPE_FORMAT_YV12:
82 return const_resource_formats_YV12;
83
84 case PIPE_FORMAT_NV12:
85 return const_resource_formats_NV12;
86
87 case PIPE_FORMAT_R8G8B8A8_UNORM:
88 return const_resource_formats_YUVA;
89
90 case PIPE_FORMAT_B8G8R8A8_UNORM:
91 return const_resource_formats_VUYA;
92
93 default:
94 return NULL;
95 }
96 }
97
98 const unsigned *
99 vl_video_buffer_plane_order(enum pipe_format format)
100 {
101 switch(format) {
102 case PIPE_FORMAT_YV12:
103 return const_resource_plane_order_YVU;
104
105 case PIPE_FORMAT_NV12:
106 case PIPE_FORMAT_R8G8B8A8_UNORM:
107 case PIPE_FORMAT_B8G8R8A8_UNORM:
108 return const_resource_plane_order_YUV;
109
110 default:
111 return NULL;
112 }
113 }
114
115 boolean
116 vl_video_buffer_is_format_supported(struct pipe_screen *screen,
117 enum pipe_format format,
118 enum pipe_video_profile profile)
119 {
120 const enum pipe_format *resource_formats;
121 unsigned i;
122
123 resource_formats = vl_video_buffer_formats(screen, format);
124 if (!resource_formats)
125 return false;
126
127 for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
128 if (!resource_formats[i])
129 continue;
130
131 if (!screen->is_format_supported(screen, resource_formats[i], PIPE_TEXTURE_2D, 0, PIPE_USAGE_STATIC))
132 return false;
133 }
134
135 return true;
136 }
137
138 unsigned
139 vl_video_buffer_max_size(struct pipe_screen *screen)
140 {
141 uint32_t max_2d_texture_level;
142
143 max_2d_texture_level = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
144
145 return 1 << (max_2d_texture_level-1);
146 }
147
148 void
149 vl_video_buffer_set_associated_data(struct pipe_video_buffer *vbuf,
150 struct pipe_video_decoder *vdec,
151 void *associated_data,
152 void (*destroy_associated_data)(void *))
153 {
154 vbuf->decoder = vdec;
155
156 if (vbuf->associated_data == associated_data)
157 return;
158
159 if (vbuf->associated_data)
160 vbuf->destroy_associated_data(vbuf->associated_data);
161
162 vbuf->associated_data = associated_data;
163 vbuf->destroy_associated_data = destroy_associated_data;
164 }
165
166 void *
167 vl_video_buffer_get_associated_data(struct pipe_video_buffer *vbuf,
168 struct pipe_video_decoder *vdec)
169 {
170 if (vbuf->decoder == vdec)
171 return vbuf->associated_data;
172 else
173 return NULL;
174 }
175
176 void
177 vl_vide_buffer_template(struct pipe_resource *templ,
178 const struct pipe_video_buffer *tmpl,
179 enum pipe_format resource_format,
180 unsigned depth, unsigned usage, unsigned plane)
181 {
182 memset(templ, 0, sizeof(*templ));
183 templ->target = depth > 1 ? PIPE_TEXTURE_3D : PIPE_TEXTURE_2D;
184 templ->format = resource_format;
185 templ->width0 = tmpl->width;
186 templ->height0 = tmpl->height;
187 templ->depth0 = depth;
188 templ->array_size = 1;
189 templ->bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
190 templ->usage = usage;
191
192 if (plane > 0) {
193 if (tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
194 templ->width0 /= 2;
195 templ->height0 /= 2;
196 } else if (tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) {
197 templ->height0 /= 2;
198 }
199 }
200 }
201
202 static void
203 vl_video_buffer_destroy(struct pipe_video_buffer *buffer)
204 {
205 struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
206 unsigned i;
207
208 assert(buf);
209
210 for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
211 pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
212 pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
213 pipe_resource_reference(&buf->resources[i], NULL);
214 }
215
216 for (i = 0; i < VL_NUM_COMPONENTS * 2; ++i)
217 pipe_surface_reference(&buf->surfaces[i], NULL);
218
219 vl_video_buffer_set_associated_data(buffer, NULL, NULL, NULL);
220
221 FREE(buffer);
222 }
223
224 static struct pipe_sampler_view **
225 vl_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)
226 {
227 struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
228 struct pipe_sampler_view sv_templ;
229 struct pipe_context *pipe;
230 unsigned i;
231
232 assert(buf);
233
234 pipe = buf->base.context;
235
236 for (i = 0; i < buf->num_planes; ++i ) {
237 if (!buf->sampler_view_planes[i]) {
238 memset(&sv_templ, 0, sizeof(sv_templ));
239 u_sampler_view_default_template(&sv_templ, buf->resources[i], buf->resources[i]->format);
240
241 if (util_format_get_nr_components(buf->resources[i]->format) == 1)
242 sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = sv_templ.swizzle_a = PIPE_SWIZZLE_RED;
243
244 buf->sampler_view_planes[i] = pipe->create_sampler_view(pipe, buf->resources[i], &sv_templ);
245 if (!buf->sampler_view_planes[i])
246 goto error;
247 }
248 }
249
250 return buf->sampler_view_planes;
251
252 error:
253 for (i = 0; i < buf->num_planes; ++i )
254 pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
255
256 return NULL;
257 }
258
259 static struct pipe_sampler_view **
260 vl_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)
261 {
262 struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
263 struct pipe_sampler_view sv_templ;
264 struct pipe_context *pipe;
265 const unsigned *plane_order;
266 unsigned i, j, component;
267
268 assert(buf);
269
270 pipe = buf->base.context;
271
272 plane_order = vl_video_buffer_plane_order(buf->base.buffer_format);
273
274 for (component = 0, i = 0; i < buf->num_planes; ++i ) {
275 struct pipe_resource *res = buf->resources[plane_order[i]];
276 unsigned nr_components = util_format_get_nr_components(res->format);
277
278 for (j = 0; j < nr_components; ++j, ++component) {
279 assert(component < VL_NUM_COMPONENTS);
280
281 if (!buf->sampler_view_components[component]) {
282 memset(&sv_templ, 0, sizeof(sv_templ));
283 u_sampler_view_default_template(&sv_templ, res, res->format);
284 sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_RED + j;
285 sv_templ.swizzle_a = PIPE_SWIZZLE_ONE;
286 buf->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ);
287 if (!buf->sampler_view_components[component])
288 goto error;
289 }
290 }
291 }
292
293 return buf->sampler_view_components;
294
295 error:
296 for (i = 0; i < VL_NUM_COMPONENTS; ++i )
297 pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
298
299 return NULL;
300 }
301
302 static struct pipe_surface **
303 vl_video_buffer_surfaces(struct pipe_video_buffer *buffer)
304 {
305 struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
306 struct pipe_surface surf_templ;
307 struct pipe_context *pipe;
308 unsigned i, j, depth, surf;
309
310 assert(buf);
311
312 pipe = buf->base.context;
313
314 depth = buffer->interlaced ? 2 : 1;
315 for (i = 0, surf = 0; i < depth; ++i ) {
316 for (j = 0; j < VL_NUM_COMPONENTS; ++j, ++surf) {
317 assert(surf < (VL_NUM_COMPONENTS * 2));
318
319 if (!buf->resources[j]) {
320 pipe_surface_reference(&buf->surfaces[surf], NULL);
321 continue;
322 }
323
324 if (!buf->surfaces[surf]) {
325 memset(&surf_templ, 0, sizeof(surf_templ));
326 surf_templ.format = buf->resources[j]->format;
327 surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
328 surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = i;
329 buf->surfaces[surf] = pipe->create_surface(pipe, buf->resources[j], &surf_templ);
330 if (!buf->surfaces[surf])
331 goto error;
332 }
333 }
334 }
335
336 return buf->surfaces;
337
338 error:
339 for (i = 0; i < (VL_NUM_COMPONENTS * 2); ++i )
340 pipe_surface_reference(&buf->surfaces[i], NULL);
341
342 return NULL;
343 }
344
345 struct pipe_video_buffer *
346 vl_video_buffer_create(struct pipe_context *pipe,
347 const struct pipe_video_buffer *tmpl)
348 {
349 const enum pipe_format *resource_formats;
350 struct pipe_video_buffer templat, *result;
351 bool pot_buffers;
352
353 assert(pipe);
354 assert(tmpl->width > 0 && tmpl->height > 0);
355
356 pot_buffers = !pipe->screen->get_video_param
357 (
358 pipe->screen,
359 PIPE_VIDEO_PROFILE_UNKNOWN,
360 PIPE_VIDEO_CAP_NPOT_TEXTURES
361 );
362
363 resource_formats = vl_video_buffer_formats(pipe->screen, tmpl->buffer_format);
364 if (!resource_formats)
365 return NULL;
366
367 templat = *tmpl;
368 templat.width = pot_buffers ? util_next_power_of_two(tmpl->width)
369 : align(tmpl->width, VL_MACROBLOCK_WIDTH);
370 templat.height = pot_buffers ? util_next_power_of_two(tmpl->height)
371 : align(tmpl->height, VL_MACROBLOCK_HEIGHT);
372
373 if (tmpl->interlaced)
374 templat.height /= 2;
375
376 result = vl_video_buffer_create_ex
377 (
378 pipe, &templat, resource_formats,
379 tmpl->interlaced ? 2 : 1, PIPE_USAGE_STATIC
380 );
381
382
383 if (result && tmpl->interlaced)
384 result->height *= 2;
385
386 return result;
387 }
388
389 struct pipe_video_buffer *
390 vl_video_buffer_create_ex(struct pipe_context *pipe,
391 const struct pipe_video_buffer *tmpl,
392 const enum pipe_format resource_formats[VL_NUM_COMPONENTS],
393 unsigned depth, unsigned usage)
394 {
395 struct pipe_resource res_tmpl;
396 struct pipe_resource *resources[VL_NUM_COMPONENTS];
397 unsigned i;
398
399 assert(pipe);
400
401 memset(resources, 0, sizeof resources);
402
403 vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[0], depth, usage, 0);
404 resources[0] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
405 if (!resources[0])
406 goto error;
407
408 if (resource_formats[1] == PIPE_FORMAT_NONE) {
409 assert(tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_444);
410 assert(resource_formats[2] == PIPE_FORMAT_NONE);
411 return vl_video_buffer_create_ex2(pipe, tmpl, resources);
412 }
413
414 vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[1], depth, usage, 1);
415 resources[1] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
416 if (!resources[1])
417 goto error;
418
419 if (resource_formats[2] == PIPE_FORMAT_NONE)
420 return vl_video_buffer_create_ex2(pipe, tmpl, resources);
421
422 vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[2], depth, usage, 2);
423 resources[2] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
424 if (!resources[2])
425 goto error;
426
427 return vl_video_buffer_create_ex2(pipe, tmpl, resources);
428
429 error:
430 for (i = 0; i < VL_NUM_COMPONENTS; ++i)
431 pipe_resource_reference(&resources[i], NULL);
432
433 return NULL;
434 }
435
436 struct pipe_video_buffer *
437 vl_video_buffer_create_ex2(struct pipe_context *pipe,
438 const struct pipe_video_buffer *tmpl,
439 struct pipe_resource *resources[VL_NUM_COMPONENTS])
440 {
441 struct vl_video_buffer *buffer;
442 unsigned i;
443
444 buffer = CALLOC_STRUCT(vl_video_buffer);
445
446 buffer->base = *tmpl;
447 buffer->base.context = pipe;
448 buffer->base.destroy = vl_video_buffer_destroy;
449 buffer->base.get_sampler_view_planes = vl_video_buffer_sampler_view_planes;
450 buffer->base.get_sampler_view_components = vl_video_buffer_sampler_view_components;
451 buffer->base.get_surfaces = vl_video_buffer_surfaces;
452 buffer->num_planes = 0;
453
454 for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
455 buffer->resources[i] = resources[i];
456 if (resources[i])
457 buffer->num_planes++;
458 }
459
460 return &buffer->base;
461 }