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