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