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