subpicture.c revision d645dc65b6c5e7d46538e98208a703f0f7a5d20b
1/************************************************************************** 2 * 3 * Copyright 2009 Younes Manton. 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 <X11/Xlibint.h> 31#include <X11/extensions/XvMClib.h> 32 33#include "pipe/p_screen.h" 34#include "pipe/p_video_decoder.h" 35#include "pipe/p_state.h" 36 37#include "util/u_memory.h" 38#include "util/u_math.h" 39#include "util/u_format.h" 40#include "util/u_sampler.h" 41#include "util/u_rect.h" 42 43#include "vl_winsys.h" 44 45#include "xvmc_private.h" 46 47#define FOURCC_RGB 0x0000003 48#define FOURCC_AI44 0x34344941 49#define FOURCC_IA44 0x34344149 50 51static enum pipe_format XvIDToPipe(int xvimage_id) 52{ 53 switch (xvimage_id) { 54 case FOURCC_RGB: 55 return PIPE_FORMAT_B8G8R8X8_UNORM; 56 57 case FOURCC_AI44: 58 return PIPE_FORMAT_A4R4_UNORM; 59 60 case FOURCC_IA44: 61 return PIPE_FORMAT_R4A4_UNORM; 62 63 default: 64 XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized Xv image ID 0x%08X.\n", xvimage_id); 65 return PIPE_FORMAT_NONE; 66 } 67} 68 69static unsigned NumPaletteEntries4XvID(int xvimage_id) 70{ 71 switch (xvimage_id) { 72 case FOURCC_RGB: 73 return 0; 74 75 case FOURCC_AI44: 76 case FOURCC_IA44: 77 return 16; 78 79 default: 80 XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized Xv image ID 0x%08X.\n", xvimage_id); 81 return 0; 82 } 83} 84 85static int PipeToComponentOrder(enum pipe_format format, char *component_order) 86{ 87 assert(component_order); 88 89 switch (format) { 90 case PIPE_FORMAT_B8G8R8X8_UNORM: 91 return 0; 92 93 case PIPE_FORMAT_R4A4_UNORM: 94 case PIPE_FORMAT_A4R4_UNORM: 95 component_order[0] = 'Y'; 96 component_order[1] = 'U'; 97 component_order[2] = 'V'; 98 component_order[3] = 'A'; 99 return 4; 100 101 default: 102 XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized PIPE_FORMAT 0x%08X.\n", format); 103 component_order[0] = 0; 104 component_order[1] = 0; 105 component_order[2] = 0; 106 component_order[3] = 0; 107 return 0; 108 } 109} 110 111static Status Validate(Display *dpy, XvPortID port, int surface_type_id, int xvimage_id) 112{ 113 XvImageFormatValues *subpictures; 114 int num_subpics; 115 unsigned int i; 116 117 subpictures = XvMCListSubpictureTypes(dpy, port, surface_type_id, &num_subpics); 118 if (num_subpics < 1) { 119 if (subpictures) 120 XFree(subpictures); 121 return BadMatch; 122 } 123 if (!subpictures) 124 return BadAlloc; 125 126 for (i = 0; i < num_subpics; ++i) { 127 if (subpictures[i].id == xvimage_id) { 128 XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested subpicture format.\n" \ 129 "[XvMC] port=%u\n" \ 130 "[XvMC] surface id=0x%08X\n" \ 131 "[XvMC] image id=0x%08X\n" \ 132 "[XvMC] type=%08X\n" \ 133 "[XvMC] byte order=%08X\n" \ 134 "[XvMC] bits per pixel=%u\n" \ 135 "[XvMC] format=%08X\n" \ 136 "[XvMC] num planes=%d\n", 137 port, surface_type_id, xvimage_id, subpictures[i].type, subpictures[i].byte_order, 138 subpictures[i].bits_per_pixel, subpictures[i].format, subpictures[i].num_planes); 139 if (subpictures[i].type == XvRGB) { 140 XVMC_MSG(XVMC_TRACE, "[XvMC] depth=%d\n" \ 141 "[XvMC] red mask=0x%08X\n" \ 142 "[XvMC] green mask=0x%08X\n" \ 143 "[XvMC] blue mask=0x%08X\n", 144 subpictures[i].depth, subpictures[i].red_mask, 145 subpictures[i].green_mask, subpictures[i].blue_mask); 146 } 147 else if (subpictures[i].type == XvYUV) { 148 XVMC_MSG(XVMC_TRACE, "[XvMC] y sample bits=0x%08X\n" \ 149 "[XvMC] u sample bits=0x%08X\n" \ 150 "[XvMC] v sample bits=0x%08X\n" \ 151 "[XvMC] horz y period=%u\n" \ 152 "[XvMC] horz u period=%u\n" \ 153 "[XvMC] horz v period=%u\n" \ 154 "[XvMC] vert y period=%u\n" \ 155 "[XvMC] vert u period=%u\n" \ 156 "[XvMC] vert v period=%u\n", 157 subpictures[i].y_sample_bits, subpictures[i].u_sample_bits, subpictures[i].v_sample_bits, 158 subpictures[i].horz_y_period, subpictures[i].horz_u_period, subpictures[i].horz_v_period, 159 subpictures[i].vert_y_period, subpictures[i].vert_u_period, subpictures[i].vert_v_period); 160 } 161 break; 162 } 163 } 164 165 XFree(subpictures); 166 167 return i < num_subpics ? Success : BadMatch; 168} 169 170static void 171upload_sampler(struct pipe_context *pipe, struct pipe_sampler_view *dst, 172 const struct pipe_box *dst_box, const void *src, unsigned src_stride, 173 unsigned src_x, unsigned src_y) 174{ 175 struct pipe_transfer *transfer; 176 void *map; 177 178 transfer = pipe->get_transfer(pipe, dst->texture, 0, PIPE_TRANSFER_WRITE, dst_box); 179 if (!transfer) 180 return; 181 182 map = pipe->transfer_map(pipe, transfer); 183 if (map) { 184 util_copy_rect(map, dst->texture->format, transfer->stride, 0, 0, 185 dst_box->width, dst_box->height, 186 src, src_stride, src_x, src_y); 187 188 pipe->transfer_unmap(pipe, transfer); 189 } 190 191 pipe->transfer_destroy(pipe, transfer); 192} 193 194PUBLIC 195Status XvMCCreateSubpicture(Display *dpy, XvMCContext *context, XvMCSubpicture *subpicture, 196 unsigned short width, unsigned short height, int xvimage_id) 197{ 198 XvMCContextPrivate *context_priv; 199 XvMCSubpicturePrivate *subpicture_priv; 200 struct pipe_context *pipe; 201 struct pipe_resource tex_templ, *tex; 202 struct pipe_sampler_view sampler_templ; 203 Status ret; 204 205 XVMC_MSG(XVMC_TRACE, "[XvMC] Creating subpicture %p.\n", subpicture); 206 207 assert(dpy); 208 209 if (!context) 210 return XvMCBadContext; 211 212 context_priv = context->privData; 213 pipe = context_priv->pipe; 214 215 if (!subpicture) 216 return XvMCBadSubpicture; 217 218 if (width > context_priv->subpicture_max_width || 219 height > context_priv->subpicture_max_height) 220 return BadValue; 221 222 ret = Validate(dpy, context->port, context->surface_type_id, xvimage_id); 223 if (ret != Success) 224 return ret; 225 226 subpicture_priv = CALLOC(1, sizeof(XvMCSubpicturePrivate)); 227 if (!subpicture_priv) 228 return BadAlloc; 229 230 memset(&tex_templ, 0, sizeof(tex_templ)); 231 tex_templ.target = PIPE_TEXTURE_2D; 232 tex_templ.format = XvIDToPipe(xvimage_id); 233 tex_templ.last_level = 0; 234 if (pipe->screen->get_video_param(pipe->screen, 235 PIPE_VIDEO_PROFILE_UNKNOWN, 236 PIPE_VIDEO_CAP_NPOT_TEXTURES)) { 237 tex_templ.width0 = width; 238 tex_templ.height0 = height; 239 } 240 else { 241 tex_templ.width0 = util_next_power_of_two(width); 242 tex_templ.height0 = util_next_power_of_two(height); 243 } 244 tex_templ.depth0 = 1; 245 tex_templ.array_size = 1; 246 tex_templ.usage = PIPE_USAGE_DYNAMIC; 247 tex_templ.bind = PIPE_BIND_SAMPLER_VIEW; 248 tex_templ.flags = 0; 249 250 tex = pipe->screen->resource_create(pipe->screen, &tex_templ); 251 252 memset(&sampler_templ, 0, sizeof(sampler_templ)); 253 u_sampler_view_default_template(&sampler_templ, tex, tex->format); 254 255 subpicture_priv->sampler = pipe->create_sampler_view(pipe, tex, &sampler_templ); 256 pipe_resource_reference(&tex, NULL); 257 if (!subpicture_priv->sampler) { 258 FREE(subpicture_priv); 259 return BadAlloc; 260 } 261 262 subpicture_priv->context = context; 263 subpicture->subpicture_id = XAllocID(dpy); 264 subpicture->context_id = context->context_id; 265 subpicture->xvimage_id = xvimage_id; 266 subpicture->width = width; 267 subpicture->height = height; 268 subpicture->num_palette_entries = NumPaletteEntries4XvID(xvimage_id); 269 subpicture->entry_bytes = PipeToComponentOrder(tex_templ.format, subpicture->component_order); 270 subpicture->privData = subpicture_priv; 271 272 if (subpicture->num_palette_entries > 0) { 273 tex_templ.target = PIPE_TEXTURE_1D; 274 tex_templ.format = PIPE_FORMAT_R8G8B8X8_UNORM; 275 tex_templ.width0 = subpicture->num_palette_entries; 276 tex_templ.height0 = 1; 277 tex_templ.usage = PIPE_USAGE_STATIC; 278 279 tex = pipe->screen->resource_create(pipe->screen, &tex_templ); 280 281 memset(&sampler_templ, 0, sizeof(sampler_templ)); 282 u_sampler_view_default_template(&sampler_templ, tex, tex->format); 283 sampler_templ.swizzle_a = PIPE_SWIZZLE_ONE; 284 subpicture_priv->palette = pipe->create_sampler_view(pipe, tex, &sampler_templ); 285 pipe_resource_reference(&tex, NULL); 286 if (!subpicture_priv->sampler) { 287 FREE(subpicture_priv); 288 return BadAlloc; 289 } 290 } 291 292 SyncHandle(); 293 294 XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p created.\n", subpicture); 295 296 return Success; 297} 298 299PUBLIC 300Status XvMCClearSubpicture(Display *dpy, XvMCSubpicture *subpicture, short x, short y, 301 unsigned short width, unsigned short height, unsigned int color) 302{ 303 XvMCSubpicturePrivate *subpicture_priv; 304 XvMCContextPrivate *context_priv; 305 struct pipe_context *pipe; 306 struct pipe_sampler_view *dst; 307 struct pipe_box dst_box = {x, y, 0, width, height, 1}; 308 struct pipe_transfer *transfer; 309 union util_color uc; 310 void *map; 311 312 assert(dpy); 313 314 if (!subpicture) 315 return XvMCBadSubpicture; 316 317 /* Convert color to float */ 318 util_format_read_4f(PIPE_FORMAT_B8G8R8A8_UNORM, 319 uc.f, 1, &color, 4, 320 0, 0, 1, 1); 321 322 subpicture_priv = subpicture->privData; 323 context_priv = subpicture_priv->context->privData; 324 pipe = context_priv->pipe; 325 dst = subpicture_priv->sampler; 326 327 /* TODO: Assert clear rect is within bounds? Or clip? */ 328 transfer = pipe->get_transfer(pipe, dst->texture, 0, PIPE_TRANSFER_WRITE, &dst_box); 329 if (!transfer) 330 return XvMCBadSubpicture; 331 332 map = pipe->transfer_map(pipe, transfer); 333 if (map) { 334 util_fill_rect(map, dst->texture->format, transfer->stride, 0, 0, 335 dst_box.width, dst_box.height, &uc); 336 337 pipe->transfer_unmap(pipe, transfer); 338 } 339 340 pipe->transfer_destroy(pipe, transfer); 341 342 return Success; 343} 344 345PUBLIC 346Status XvMCCompositeSubpicture(Display *dpy, XvMCSubpicture *subpicture, XvImage *image, 347 short srcx, short srcy, unsigned short width, unsigned short height, 348 short dstx, short dsty) 349{ 350 XvMCSubpicturePrivate *subpicture_priv; 351 XvMCContextPrivate *context_priv; 352 struct pipe_context *pipe; 353 struct pipe_box dst_box = {dstx, dsty, 0, width, height, 1}; 354 unsigned src_stride; 355 356 XVMC_MSG(XVMC_TRACE, "[XvMC] Compositing subpicture %p.\n", subpicture); 357 358 assert(dpy); 359 360 if (!subpicture) 361 return XvMCBadSubpicture; 362 363 assert(image); 364 365 if (subpicture->xvimage_id != image->id) 366 return BadMatch; 367 368 /* No planar support for now */ 369 if (image->num_planes != 1) 370 return BadMatch; 371 372 subpicture_priv = subpicture->privData; 373 context_priv = subpicture_priv->context->privData; 374 pipe = context_priv->pipe; 375 376 /* clipping should be done by upload_sampler and regardles what the documentation 377 says image->pitches[0] doesn't seems to be in bytes, so don't use it */ 378 src_stride = image->width * util_format_get_blocksize(subpicture_priv->sampler->texture->format); 379 upload_sampler(pipe, subpicture_priv->sampler, &dst_box, image->data, src_stride, srcx, srcy); 380 381 XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p composited.\n", subpicture); 382 383 return Success; 384} 385 386PUBLIC 387Status XvMCDestroySubpicture(Display *dpy, XvMCSubpicture *subpicture) 388{ 389 XvMCSubpicturePrivate *subpicture_priv; 390 391 XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying subpicture %p.\n", subpicture); 392 393 assert(dpy); 394 395 if (!subpicture) 396 return XvMCBadSubpicture; 397 398 subpicture_priv = subpicture->privData; 399 pipe_sampler_view_reference(&subpicture_priv->sampler, NULL); 400 pipe_sampler_view_reference(&subpicture_priv->palette, NULL); 401 FREE(subpicture_priv); 402 403 XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p destroyed.\n", subpicture); 404 405 return Success; 406} 407 408PUBLIC 409Status XvMCSetSubpicturePalette(Display *dpy, XvMCSubpicture *subpicture, unsigned char *palette) 410{ 411 XvMCSubpicturePrivate *subpicture_priv; 412 XvMCContextPrivate *context_priv; 413 struct pipe_context *pipe; 414 struct pipe_box dst_box = {0, 0, 0, 0, 1, 1}; 415 416 assert(dpy); 417 assert(palette); 418 419 if (!subpicture) 420 return XvMCBadSubpicture; 421 422 subpicture_priv = subpicture->privData; 423 context_priv = subpicture_priv->context->privData; 424 pipe = context_priv->pipe; 425 426 dst_box.width = subpicture->num_palette_entries; 427 428 upload_sampler(pipe, subpicture_priv->palette, &dst_box, palette, 0, 0, 0); 429 430 XVMC_MSG(XVMC_TRACE, "[XvMC] Palette of Subpicture %p set.\n", subpicture); 431 432 return Success; 433} 434 435PUBLIC 436Status XvMCBlendSubpicture(Display *dpy, XvMCSurface *target_surface, XvMCSubpicture *subpicture, 437 short subx, short suby, unsigned short subw, unsigned short subh, 438 short surfx, short surfy, unsigned short surfw, unsigned short surfh) 439{ 440 struct u_rect src_rect = {subx, subx + subw, suby, suby + subh}; 441 struct u_rect dst_rect = {surfx, surfx + surfw, surfy, surfy + surfh}; 442 443 XvMCSurfacePrivate *surface_priv; 444 XvMCSubpicturePrivate *subpicture_priv; 445 446 XVMC_MSG(XVMC_TRACE, "[XvMC] Associating subpicture %p with surface %p.\n", subpicture, target_surface); 447 448 assert(dpy); 449 450 if (!target_surface) 451 return XvMCBadSurface; 452 453 if (!subpicture) 454 return XvMCBadSubpicture; 455 456 if (target_surface->context_id != subpicture->context_id) 457 return BadMatch; 458 459 /* TODO: Verify against subpicture independent scaling */ 460 461 surface_priv = target_surface->privData; 462 subpicture_priv = subpicture->privData; 463 464 /* TODO: Assert rects are within bounds? Or clip? */ 465 subpicture_priv->src_rect = src_rect; 466 subpicture_priv->dst_rect = dst_rect; 467 468 surface_priv->subpicture = subpicture; 469 subpicture_priv->surface = target_surface; 470 471 return Success; 472} 473 474PUBLIC 475Status XvMCBlendSubpicture2(Display *dpy, XvMCSurface *source_surface, XvMCSurface *target_surface, 476 XvMCSubpicture *subpicture, short subx, short suby, unsigned short subw, unsigned short subh, 477 short surfx, short surfy, unsigned short surfw, unsigned short surfh) 478{ 479 assert(dpy); 480 481 if (!source_surface || !target_surface) 482 return XvMCBadSurface; 483 484 if (!subpicture) 485 return XvMCBadSubpicture; 486 487 if (source_surface->context_id != subpicture->context_id) 488 return BadMatch; 489 490 if (source_surface->context_id != subpicture->context_id) 491 return BadMatch; 492 493 /* TODO: Assert rects are within bounds? Or clip? */ 494 495 return Success; 496} 497 498PUBLIC 499Status XvMCSyncSubpicture(Display *dpy, XvMCSubpicture *subpicture) 500{ 501 assert(dpy); 502 503 if (!subpicture) 504 return XvMCBadSubpicture; 505 506 return Success; 507} 508 509PUBLIC 510Status XvMCFlushSubpicture(Display *dpy, XvMCSubpicture *subpicture) 511{ 512 assert(dpy); 513 514 if (!subpicture) 515 return XvMCBadSubpicture; 516 517 return Success; 518} 519 520PUBLIC 521Status XvMCGetSubpictureStatus(Display *dpy, XvMCSubpicture *subpicture, int *status) 522{ 523 assert(dpy); 524 525 if (!subpicture) 526 return XvMCBadSubpicture; 527 528 assert(status); 529 530 /* TODO */ 531 *status = 0; 532 533 return Success; 534} 535