Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 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 |
||
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 * |
||
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 * |
||
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 |
||
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 |
||
148 | vl_video_buffer_is_format_supported(struct pipe_screen *screen, |
||
149 | enum pipe_format format, |
||
150 | enum pipe_video_profile profile, |
||
151 | enum pipe_video_entrypoint entrypoint) |
||
152 | { |
||
153 | const enum pipe_format *resource_formats; |
||
154 | unsigned i; |
||
155 | |||
156 | resource_formats = vl_video_buffer_formats(screen, format); |
||
157 | if (!resource_formats) |
||
158 | return false; |
||
159 | |||
160 | for (i = 0; i < VL_NUM_COMPONENTS; ++i) { |
||
161 | enum pipe_format format = resource_formats[i]; |
||
162 | |||
163 | if (format == PIPE_FORMAT_NONE) |
||
164 | continue; |
||
165 | |||
166 | /* we at least need to sample from it */ |
||
167 | if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW)) |
||
168 | return false; |
||
169 | |||
170 | format = vl_video_buffer_surface_format(format); |
||
171 | if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET)) |
||
172 | return false; |
||
173 | } |
||
174 | |||
175 | return true; |
||
176 | } |
||
177 | |||
178 | unsigned |
||
179 | vl_video_buffer_max_size(struct pipe_screen *screen) |
||
180 | { |
||
181 | uint32_t max_2d_texture_level; |
||
182 | |||
183 | max_2d_texture_level = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); |
||
184 | |||
185 | return 1 << (max_2d_texture_level-1); |
||
186 | } |
||
187 | |||
188 | void |
||
189 | vl_video_buffer_set_associated_data(struct pipe_video_buffer *vbuf, |
||
190 | struct pipe_video_codec *vcodec, |
||
191 | void *associated_data, |
||
192 | void (*destroy_associated_data)(void *)) |
||
193 | { |
||
194 | vbuf->codec = vcodec; |
||
195 | |||
196 | if (vbuf->associated_data == associated_data) |
||
197 | return; |
||
198 | |||
199 | if (vbuf->associated_data) |
||
200 | vbuf->destroy_associated_data(vbuf->associated_data); |
||
201 | |||
202 | vbuf->associated_data = associated_data; |
||
203 | vbuf->destroy_associated_data = destroy_associated_data; |
||
204 | } |
||
205 | |||
206 | void * |
||
207 | vl_video_buffer_get_associated_data(struct pipe_video_buffer *vbuf, |
||
208 | struct pipe_video_codec *vcodec) |
||
209 | { |
||
210 | if (vbuf->codec == vcodec) |
||
211 | return vbuf->associated_data; |
||
212 | else |
||
213 | return NULL; |
||
214 | } |
||
215 | |||
216 | void |
||
217 | vl_video_buffer_template(struct pipe_resource *templ, |
||
218 | const struct pipe_video_buffer *tmpl, |
||
219 | enum pipe_format resource_format, |
||
220 | unsigned depth, unsigned array_size, |
||
221 | unsigned usage, unsigned plane) |
||
222 | { |
||
223 | memset(templ, 0, sizeof(*templ)); |
||
224 | if (depth > 1) |
||
225 | templ->target = PIPE_TEXTURE_3D; |
||
226 | else if (array_size > 1) |
||
227 | templ->target = PIPE_TEXTURE_2D_ARRAY; |
||
228 | else |
||
229 | templ->target = PIPE_TEXTURE_2D; |
||
230 | templ->format = resource_format; |
||
231 | templ->width0 = tmpl->width; |
||
232 | templ->height0 = tmpl->height; |
||
233 | templ->depth0 = depth; |
||
234 | templ->array_size = array_size; |
||
235 | templ->bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; |
||
236 | templ->usage = usage; |
||
237 | |||
238 | if (plane > 0) { |
||
239 | if (tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) { |
||
240 | templ->width0 /= 2; |
||
241 | templ->height0 /= 2; |
||
242 | } else if (tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) { |
||
243 | templ->width0 /= 2; |
||
244 | } |
||
245 | } |
||
246 | } |
||
247 | |||
248 | static void |
||
249 | vl_video_buffer_destroy(struct pipe_video_buffer *buffer) |
||
250 | { |
||
251 | struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer; |
||
252 | unsigned i; |
||
253 | |||
254 | assert(buf); |
||
255 | |||
256 | for (i = 0; i < VL_NUM_COMPONENTS; ++i) { |
||
257 | pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL); |
||
258 | pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL); |
||
259 | pipe_resource_reference(&buf->resources[i], NULL); |
||
260 | } |
||
261 | |||
262 | for (i = 0; i < VL_MAX_SURFACES; ++i) |
||
263 | pipe_surface_reference(&buf->surfaces[i], NULL); |
||
264 | |||
265 | vl_video_buffer_set_associated_data(buffer, NULL, NULL, NULL); |
||
266 | |||
267 | FREE(buffer); |
||
268 | } |
||
269 | |||
270 | static struct pipe_sampler_view ** |
||
271 | vl_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer) |
||
272 | { |
||
273 | struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer; |
||
274 | struct pipe_sampler_view sv_templ; |
||
275 | struct pipe_context *pipe; |
||
276 | unsigned i; |
||
277 | |||
278 | assert(buf); |
||
279 | |||
280 | pipe = buf->base.context; |
||
281 | |||
282 | for (i = 0; i < buf->num_planes; ++i ) { |
||
283 | if (!buf->sampler_view_planes[i]) { |
||
284 | memset(&sv_templ, 0, sizeof(sv_templ)); |
||
285 | u_sampler_view_default_template(&sv_templ, buf->resources[i], buf->resources[i]->format); |
||
286 | |||
287 | if (util_format_get_nr_components(buf->resources[i]->format) == 1) |
||
288 | sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = sv_templ.swizzle_a = PIPE_SWIZZLE_RED; |
||
289 | |||
290 | buf->sampler_view_planes[i] = pipe->create_sampler_view(pipe, buf->resources[i], &sv_templ); |
||
291 | if (!buf->sampler_view_planes[i]) |
||
292 | goto error; |
||
293 | } |
||
294 | } |
||
295 | |||
296 | return buf->sampler_view_planes; |
||
297 | |||
298 | error: |
||
299 | for (i = 0; i < buf->num_planes; ++i ) |
||
300 | pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL); |
||
301 | |||
302 | return NULL; |
||
303 | } |
||
304 | |||
305 | static struct pipe_sampler_view ** |
||
306 | vl_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer) |
||
307 | { |
||
308 | struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer; |
||
309 | struct pipe_sampler_view sv_templ; |
||
310 | struct pipe_context *pipe; |
||
311 | const enum pipe_format *sampler_format; |
||
312 | const unsigned *plane_order; |
||
313 | unsigned i, j, component; |
||
314 | |||
315 | assert(buf); |
||
316 | |||
317 | pipe = buf->base.context; |
||
318 | |||
319 | sampler_format = vl_video_buffer_formats(pipe->screen, buf->base.buffer_format); |
||
320 | plane_order = vl_video_buffer_plane_order(buf->base.buffer_format); |
||
321 | |||
322 | for (component = 0, i = 0; i < buf->num_planes; ++i ) { |
||
323 | struct pipe_resource *res = buf->resources[plane_order[i]]; |
||
324 | const struct util_format_description *desc = util_format_description(res->format); |
||
325 | unsigned nr_components = util_format_get_nr_components(res->format); |
||
326 | if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) |
||
327 | nr_components = 3; |
||
328 | |||
329 | for (j = 0; j < nr_components && component < VL_NUM_COMPONENTS; ++j, ++component) { |
||
330 | if (buf->sampler_view_components[component]) |
||
331 | continue; |
||
332 | |||
333 | memset(&sv_templ, 0, sizeof(sv_templ)); |
||
334 | u_sampler_view_default_template(&sv_templ, res, sampler_format[plane_order[i]]); |
||
335 | sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_RED + j; |
||
336 | sv_templ.swizzle_a = PIPE_SWIZZLE_ONE; |
||
337 | buf->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ); |
||
338 | if (!buf->sampler_view_components[component]) |
||
339 | goto error; |
||
340 | } |
||
341 | } |
||
342 | assert(component == VL_NUM_COMPONENTS); |
||
343 | |||
344 | return buf->sampler_view_components; |
||
345 | |||
346 | error: |
||
347 | for (i = 0; i < VL_NUM_COMPONENTS; ++i ) |
||
348 | pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL); |
||
349 | |||
350 | return NULL; |
||
351 | } |
||
352 | |||
353 | static struct pipe_surface ** |
||
354 | vl_video_buffer_surfaces(struct pipe_video_buffer *buffer) |
||
355 | { |
||
356 | struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer; |
||
357 | struct pipe_surface surf_templ; |
||
358 | struct pipe_context *pipe; |
||
359 | unsigned i, j, array_size, surf; |
||
360 | |||
361 | assert(buf); |
||
362 | |||
363 | pipe = buf->base.context; |
||
364 | |||
365 | array_size = buffer->interlaced ? 2 : 1; |
||
366 | for (i = 0, surf = 0; i < VL_NUM_COMPONENTS; ++i) { |
||
367 | for (j = 0; j < array_size; ++j, ++surf) { |
||
368 | assert(surf < VL_MAX_SURFACES); |
||
369 | |||
370 | if (!buf->resources[i]) { |
||
371 | pipe_surface_reference(&buf->surfaces[surf], NULL); |
||
372 | continue; |
||
373 | } |
||
374 | |||
375 | if (!buf->surfaces[surf]) { |
||
376 | memset(&surf_templ, 0, sizeof(surf_templ)); |
||
377 | surf_templ.format = vl_video_buffer_surface_format(buf->resources[i]->format); |
||
378 | surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = j; |
||
379 | buf->surfaces[surf] = pipe->create_surface(pipe, buf->resources[i], &surf_templ); |
||
380 | if (!buf->surfaces[surf]) |
||
381 | goto error; |
||
382 | } |
||
383 | } |
||
384 | } |
||
385 | |||
386 | return buf->surfaces; |
||
387 | |||
388 | error: |
||
389 | for (i = 0; i < VL_MAX_SURFACES; ++i ) |
||
390 | pipe_surface_reference(&buf->surfaces[i], NULL); |
||
391 | |||
392 | return NULL; |
||
393 | } |
||
394 | |||
395 | struct pipe_video_buffer * |
||
396 | vl_video_buffer_create(struct pipe_context *pipe, |
||
397 | const struct pipe_video_buffer *tmpl) |
||
398 | { |
||
399 | const enum pipe_format *resource_formats; |
||
400 | struct pipe_video_buffer templat, *result; |
||
401 | bool pot_buffers; |
||
402 | |||
403 | assert(pipe); |
||
404 | assert(tmpl->width > 0 && tmpl->height > 0); |
||
405 | |||
406 | pot_buffers = !pipe->screen->get_video_param |
||
407 | ( |
||
408 | pipe->screen, |
||
409 | PIPE_VIDEO_PROFILE_UNKNOWN, |
||
410 | PIPE_VIDEO_ENTRYPOINT_UNKNOWN, |
||
411 | PIPE_VIDEO_CAP_NPOT_TEXTURES |
||
412 | ); |
||
413 | |||
414 | resource_formats = vl_video_buffer_formats(pipe->screen, tmpl->buffer_format); |
||
415 | if (!resource_formats) |
||
416 | return NULL; |
||
417 | |||
418 | templat = *tmpl; |
||
419 | templat.width = pot_buffers ? util_next_power_of_two(tmpl->width) |
||
420 | : align(tmpl->width, VL_MACROBLOCK_WIDTH); |
||
421 | templat.height = pot_buffers ? util_next_power_of_two(tmpl->height) |
||
422 | : align(tmpl->height, VL_MACROBLOCK_HEIGHT); |
||
423 | |||
424 | if (tmpl->interlaced) |
||
425 | templat.height /= 2; |
||
426 | |||
427 | result = vl_video_buffer_create_ex |
||
428 | ( |
||
429 | pipe, &templat, resource_formats, |
||
430 | 1, tmpl->interlaced ? 2 : 1, PIPE_USAGE_DEFAULT |
||
431 | ); |
||
432 | |||
433 | |||
434 | if (result && tmpl->interlaced) |
||
435 | result->height *= 2; |
||
436 | |||
437 | return result; |
||
438 | } |
||
439 | |||
440 | struct pipe_video_buffer * |
||
441 | vl_video_buffer_create_ex(struct pipe_context *pipe, |
||
442 | const struct pipe_video_buffer *tmpl, |
||
443 | const enum pipe_format resource_formats[VL_NUM_COMPONENTS], |
||
444 | unsigned depth, unsigned array_size, unsigned usage) |
||
445 | { |
||
446 | struct pipe_resource res_tmpl; |
||
447 | struct pipe_resource *resources[VL_NUM_COMPONENTS]; |
||
448 | unsigned i; |
||
449 | |||
450 | assert(pipe); |
||
451 | |||
452 | memset(resources, 0, sizeof resources); |
||
453 | |||
454 | vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[0], depth, array_size, usage, 0); |
||
455 | resources[0] = pipe->screen->resource_create(pipe->screen, &res_tmpl); |
||
456 | if (!resources[0]) |
||
457 | goto error; |
||
458 | |||
459 | if (resource_formats[1] == PIPE_FORMAT_NONE) { |
||
460 | assert(resource_formats[2] == PIPE_FORMAT_NONE); |
||
461 | return vl_video_buffer_create_ex2(pipe, tmpl, resources); |
||
462 | } |
||
463 | |||
464 | vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[1], depth, array_size, usage, 1); |
||
465 | resources[1] = pipe->screen->resource_create(pipe->screen, &res_tmpl); |
||
466 | if (!resources[1]) |
||
467 | goto error; |
||
468 | |||
469 | if (resource_formats[2] == PIPE_FORMAT_NONE) |
||
470 | return vl_video_buffer_create_ex2(pipe, tmpl, resources); |
||
471 | |||
472 | vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[2], depth, array_size, usage, 2); |
||
473 | resources[2] = pipe->screen->resource_create(pipe->screen, &res_tmpl); |
||
474 | if (!resources[2]) |
||
475 | goto error; |
||
476 | |||
477 | return vl_video_buffer_create_ex2(pipe, tmpl, resources); |
||
478 | |||
479 | error: |
||
480 | for (i = 0; i < VL_NUM_COMPONENTS; ++i) |
||
481 | pipe_resource_reference(&resources[i], NULL); |
||
482 | |||
483 | return NULL; |
||
484 | } |
||
485 | |||
486 | struct pipe_video_buffer * |
||
487 | vl_video_buffer_create_ex2(struct pipe_context *pipe, |
||
488 | const struct pipe_video_buffer *tmpl, |
||
489 | struct pipe_resource *resources[VL_NUM_COMPONENTS]) |
||
490 | { |
||
491 | struct vl_video_buffer *buffer; |
||
492 | unsigned i; |
||
493 | |||
494 | buffer = CALLOC_STRUCT(vl_video_buffer); |
||
495 | if (!buffer) |
||
496 | return NULL; |
||
497 | |||
498 | buffer->base = *tmpl; |
||
499 | buffer->base.context = pipe; |
||
500 | buffer->base.destroy = vl_video_buffer_destroy; |
||
501 | buffer->base.get_sampler_view_planes = vl_video_buffer_sampler_view_planes; |
||
502 | buffer->base.get_sampler_view_components = vl_video_buffer_sampler_view_components; |
||
503 | buffer->base.get_surfaces = vl_video_buffer_surfaces; |
||
504 | buffer->num_planes = 0; |
||
505 | |||
506 | for (i = 0; i < VL_NUM_COMPONENTS; ++i) { |
||
507 | buffer->resources[i] = resources[i]; |
||
508 | if (resources[i]) |
||
509 | buffer->num_planes++; |
||
510 | } |
||
511 | |||
512 | return &buffer->base; |
||
513 | }>>>>>>>>>>>>>>><>> |