vl_video_buffer.c revision 9f9628c72bb16d7d64c9b38671dff8eabd2e7681
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, depth, surf; 289 290 assert(buf); 291 292 pipe = buf->base.context; 293 294 depth = buffer->interlaced ? 2 : 1; 295 for (i = 0, surf = 0; i < depth; ++i ) { 296 for (j = 0; j < VL_MAX_PLANES; ++j, ++surf) { 297 assert(surf < (VL_MAX_PLANES * 2)); 298 299 if (!buf->resources[j]) { 300 pipe_surface_reference(&buf->surfaces[surf], NULL); 301 continue; 302 } 303 304 if (!buf->surfaces[surf]) { 305 memset(&surf_templ, 0, sizeof(surf_templ)); 306 surf_templ.format = buf->resources[j]->format; 307 surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; 308 surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = i; 309 buf->surfaces[surf] = pipe->create_surface(pipe, buf->resources[j], &surf_templ); 310 if (!buf->surfaces[surf]) 311 goto error; 312 } 313 } 314 } 315 316 return buf->surfaces; 317 318error: 319 for (i = 0; i < (VL_MAX_PLANES * 2); ++i ) 320 pipe_surface_reference(&buf->surfaces[i], NULL); 321 322 return NULL; 323} 324 325struct pipe_video_buffer * 326vl_video_buffer_create(struct pipe_context *pipe, 327 const struct pipe_video_buffer *tmpl) 328{ 329 const enum pipe_format *resource_formats; 330 struct pipe_video_buffer templat, *result; 331 bool pot_buffers; 332 333 assert(pipe); 334 assert(tmpl->width > 0 && tmpl->height > 0); 335 336 pot_buffers = !pipe->screen->get_video_param 337 ( 338 pipe->screen, 339 PIPE_VIDEO_PROFILE_UNKNOWN, 340 PIPE_VIDEO_CAP_NPOT_TEXTURES 341 ); 342 343 resource_formats = vl_video_buffer_formats(pipe->screen, tmpl->buffer_format); 344 if (!resource_formats) 345 return NULL; 346 347 templat = *tmpl; 348 templat.width = pot_buffers ? util_next_power_of_two(tmpl->width) 349 : align(tmpl->width, MACROBLOCK_WIDTH); 350 templat.height = pot_buffers ? util_next_power_of_two(tmpl->height) 351 : align(tmpl->height, MACROBLOCK_HEIGHT); 352 353 if (tmpl->interlaced) 354 templat.height /= 2; 355 356 result = vl_video_buffer_create_ex 357 ( 358 pipe, &templat, resource_formats, 359 tmpl->interlaced ? 2 : 1, PIPE_USAGE_STATIC 360 ); 361 362 363 if (result && tmpl->interlaced) 364 result->height *= 2; 365 366 return result; 367} 368 369struct pipe_video_buffer * 370vl_video_buffer_create_ex(struct pipe_context *pipe, 371 const struct pipe_video_buffer *tmpl, 372 const enum pipe_format resource_formats[VL_MAX_PLANES], 373 unsigned depth, unsigned usage) 374{ 375 struct pipe_resource res_tmpl; 376 struct pipe_resource *resources[VL_MAX_PLANES]; 377 unsigned i; 378 379 assert(pipe); 380 381 memset(resources, 0, sizeof resources); 382 383 vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[0], depth, usage, 0); 384 resources[0] = pipe->screen->resource_create(pipe->screen, &res_tmpl); 385 if (!resources[0]) 386 goto error; 387 388 if (resource_formats[1] == PIPE_FORMAT_NONE) { 389 assert(tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_444); 390 assert(resource_formats[2] == PIPE_FORMAT_NONE); 391 return vl_video_buffer_create_ex2(pipe, tmpl, resources); 392 } 393 394 vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[1], depth, usage, 1); 395 resources[1] = pipe->screen->resource_create(pipe->screen, &res_tmpl); 396 if (!resources[1]) 397 goto error; 398 399 if (resource_formats[2] == PIPE_FORMAT_NONE) 400 return vl_video_buffer_create_ex2(pipe, tmpl, resources); 401 402 vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[2], depth, usage, 2); 403 resources[2] = pipe->screen->resource_create(pipe->screen, &res_tmpl); 404 if (!resources[2]) 405 goto error; 406 407 return vl_video_buffer_create_ex2(pipe, tmpl, resources); 408 409error: 410 for (i = 0; i < VL_MAX_PLANES; ++i) 411 pipe_resource_reference(&resources[i], NULL); 412 413 return NULL; 414} 415 416struct pipe_video_buffer * 417vl_video_buffer_create_ex2(struct pipe_context *pipe, 418 const struct pipe_video_buffer *tmpl, 419 struct pipe_resource *resources[VL_MAX_PLANES]) 420{ 421 struct vl_video_buffer *buffer; 422 unsigned i; 423 424 buffer = CALLOC_STRUCT(vl_video_buffer); 425 426 buffer->base = *tmpl; 427 buffer->base.context = pipe; 428 buffer->base.destroy = vl_video_buffer_destroy; 429 buffer->base.get_sampler_view_planes = vl_video_buffer_sampler_view_planes; 430 buffer->base.get_sampler_view_components = vl_video_buffer_sampler_view_components; 431 buffer->base.get_surfaces = vl_video_buffer_surfaces; 432 buffer->num_planes = 0; 433 434 for (i = 0; i < VL_MAX_PLANES; ++i) { 435 buffer->resources[i] = resources[i]; 436 if (resources[i]) 437 buffer->num_planes++; 438 } 439 440 return &buffer->base; 441} 442