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 VMWARE 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_codec.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_surface.h" 42#include "util/u_rect.h" 43#include "vl/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_R4A4_UNORM; 59 60 case FOURCC_IA44: 61 return PIPE_FORMAT_A4R4_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_A4R4_UNORM: 94 case PIPE_FORMAT_R4A4_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 int i; 116 117 subpictures = XvMCListSubpictureTypes(dpy, port, surface_type_id, &num_subpics); 118 if (num_subpics < 1) { 119 free(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 free(subpictures); 165 166 return i < num_subpics ? Success : BadMatch; 167} 168 169static void 170upload_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 map = pipe->transfer_map(pipe, dst->texture, 0, PIPE_TRANSFER_WRITE, 178 dst_box, &transfer); 179 if (!map) 180 return; 181 182 util_copy_rect(map, dst->texture->format, transfer->stride, 0, 0, 183 dst_box->width, dst_box->height, 184 src, src_stride, src_x, src_y); 185 186 pipe->transfer_unmap(pipe, transfer); 187} 188 189PUBLIC 190Status XvMCCreateSubpicture(Display *dpy, XvMCContext *context, XvMCSubpicture *subpicture, 191 unsigned short width, unsigned short height, int xvimage_id) 192{ 193 XvMCContextPrivate *context_priv; 194 XvMCSubpicturePrivate *subpicture_priv; 195 struct pipe_context *pipe; 196 struct pipe_resource tex_templ, *tex; 197 struct pipe_sampler_view sampler_templ; 198 Status ret; 199 200 XVMC_MSG(XVMC_TRACE, "[XvMC] Creating subpicture %p.\n", subpicture); 201 202 assert(dpy); 203 204 if (!context) 205 return XvMCBadContext; 206 207 context_priv = context->privData; 208 pipe = context_priv->pipe; 209 210 if (!subpicture) 211 return XvMCBadSubpicture; 212 213 if (width > context_priv->subpicture_max_width || 214 height > context_priv->subpicture_max_height) 215 return BadValue; 216 217 ret = Validate(dpy, context->port, context->surface_type_id, xvimage_id); 218 if (ret != Success) 219 return ret; 220 221 subpicture_priv = CALLOC(1, sizeof(XvMCSubpicturePrivate)); 222 if (!subpicture_priv) 223 return BadAlloc; 224 225 memset(&tex_templ, 0, sizeof(tex_templ)); 226 tex_templ.target = PIPE_TEXTURE_2D; 227 tex_templ.format = XvIDToPipe(xvimage_id); 228 tex_templ.last_level = 0; 229 if (pipe->screen->get_video_param(pipe->screen, 230 PIPE_VIDEO_PROFILE_UNKNOWN, 231 PIPE_VIDEO_ENTRYPOINT_UNKNOWN, 232 PIPE_VIDEO_CAP_NPOT_TEXTURES)) { 233 tex_templ.width0 = width; 234 tex_templ.height0 = height; 235 } 236 else { 237 tex_templ.width0 = util_next_power_of_two(width); 238 tex_templ.height0 = util_next_power_of_two(height); 239 } 240 tex_templ.depth0 = 1; 241 tex_templ.array_size = 1; 242 tex_templ.usage = PIPE_USAGE_DYNAMIC; 243 tex_templ.bind = PIPE_BIND_SAMPLER_VIEW; 244 tex_templ.flags = 0; 245 246 tex = pipe->screen->resource_create(pipe->screen, &tex_templ); 247 248 memset(&sampler_templ, 0, sizeof(sampler_templ)); 249 u_sampler_view_default_template(&sampler_templ, tex, tex->format); 250 251 subpicture_priv->sampler = pipe->create_sampler_view(pipe, tex, &sampler_templ); 252 pipe_resource_reference(&tex, NULL); 253 if (!subpicture_priv->sampler) { 254 FREE(subpicture_priv); 255 return BadAlloc; 256 } 257 258 subpicture_priv->context = context; 259 subpicture->subpicture_id = XAllocID(dpy); 260 subpicture->context_id = context->context_id; 261 subpicture->xvimage_id = xvimage_id; 262 subpicture->width = width; 263 subpicture->height = height; 264 subpicture->num_palette_entries = NumPaletteEntries4XvID(xvimage_id); 265 subpicture->entry_bytes = PipeToComponentOrder(tex_templ.format, subpicture->component_order); 266 subpicture->privData = subpicture_priv; 267 268 if (subpicture->num_palette_entries > 0) { 269 tex_templ.target = PIPE_TEXTURE_1D; 270 tex_templ.format = PIPE_FORMAT_R8G8B8X8_UNORM; 271 tex_templ.width0 = subpicture->num_palette_entries; 272 tex_templ.height0 = 1; 273 tex_templ.usage = PIPE_USAGE_DEFAULT; 274 275 tex = pipe->screen->resource_create(pipe->screen, &tex_templ); 276 277 memset(&sampler_templ, 0, sizeof(sampler_templ)); 278 u_sampler_view_default_template(&sampler_templ, tex, tex->format); 279 sampler_templ.swizzle_a = PIPE_SWIZZLE_1; 280 subpicture_priv->palette = pipe->create_sampler_view(pipe, tex, &sampler_templ); 281 pipe_resource_reference(&tex, NULL); 282 if (!subpicture_priv->sampler) { 283 FREE(subpicture_priv); 284 return BadAlloc; 285 } 286 } 287 288 SyncHandle(); 289 290 XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p created.\n", subpicture); 291 292 return Success; 293} 294 295PUBLIC 296Status XvMCClearSubpicture(Display *dpy, XvMCSubpicture *subpicture, short x, short y, 297 unsigned short width, unsigned short height, unsigned int color) 298{ 299 XvMCSubpicturePrivate *subpicture_priv; 300 XvMCContextPrivate *context_priv; 301 struct pipe_context *pipe; 302 struct pipe_sampler_view *dst; 303 struct pipe_box dst_box = {x, y, 0, width, height, 1}; 304 struct pipe_transfer *transfer; 305 union util_color uc; 306 void *map; 307 308 assert(dpy); 309 310 if (!subpicture) 311 return XvMCBadSubpicture; 312 313 /* Convert color to float */ 314 util_format_read_4f(PIPE_FORMAT_B8G8R8A8_UNORM, 315 uc.f, 1, &color, 4, 316 0, 0, 1, 1); 317 318 subpicture_priv = subpicture->privData; 319 context_priv = subpicture_priv->context->privData; 320 pipe = context_priv->pipe; 321 dst = subpicture_priv->sampler; 322 323 /* TODO: Assert clear rect is within bounds? Or clip? */ 324 map = pipe->transfer_map(pipe, dst->texture, 0, PIPE_TRANSFER_WRITE, 325 &dst_box, &transfer); 326 if (!map) 327 return XvMCBadSubpicture; 328 329 util_fill_rect(map, dst->texture->format, transfer->stride, 0, 0, 330 dst_box.width, dst_box.height, &uc); 331 332 pipe->transfer_unmap(pipe, transfer); 333 return Success; 334} 335 336PUBLIC 337Status XvMCCompositeSubpicture(Display *dpy, XvMCSubpicture *subpicture, XvImage *image, 338 short srcx, short srcy, unsigned short width, unsigned short height, 339 short dstx, short dsty) 340{ 341 XvMCSubpicturePrivate *subpicture_priv; 342 XvMCContextPrivate *context_priv; 343 struct pipe_context *pipe; 344 struct pipe_box dst_box = {dstx, dsty, 0, width, height, 1}; 345 unsigned src_stride; 346 347 XVMC_MSG(XVMC_TRACE, "[XvMC] Compositing subpicture %p.\n", subpicture); 348 349 assert(dpy); 350 351 if (!subpicture) 352 return XvMCBadSubpicture; 353 354 assert(image); 355 356 if (subpicture->xvimage_id != image->id) 357 return BadMatch; 358 359 /* No planar support for now */ 360 if (image->num_planes != 1) 361 return BadMatch; 362 363 subpicture_priv = subpicture->privData; 364 context_priv = subpicture_priv->context->privData; 365 pipe = context_priv->pipe; 366 367 /* clipping should be done by upload_sampler and regardles what the documentation 368 says image->pitches[0] doesn't seems to be in bytes, so don't use it */ 369 src_stride = image->width * util_format_get_blocksize(subpicture_priv->sampler->texture->format); 370 upload_sampler(pipe, subpicture_priv->sampler, &dst_box, image->data, src_stride, srcx, srcy); 371 372 XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p composited.\n", subpicture); 373 374 return Success; 375} 376 377PUBLIC 378Status XvMCDestroySubpicture(Display *dpy, XvMCSubpicture *subpicture) 379{ 380 XvMCSubpicturePrivate *subpicture_priv; 381 382 XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying subpicture %p.\n", subpicture); 383 384 assert(dpy); 385 386 if (!subpicture) 387 return XvMCBadSubpicture; 388 389 subpicture_priv = subpicture->privData; 390 pipe_sampler_view_reference(&subpicture_priv->sampler, NULL); 391 pipe_sampler_view_reference(&subpicture_priv->palette, NULL); 392 FREE(subpicture_priv); 393 394 XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p destroyed.\n", subpicture); 395 396 return Success; 397} 398 399PUBLIC 400Status XvMCSetSubpicturePalette(Display *dpy, XvMCSubpicture *subpicture, unsigned char *palette) 401{ 402 XvMCSubpicturePrivate *subpicture_priv; 403 XvMCContextPrivate *context_priv; 404 struct pipe_context *pipe; 405 struct pipe_box dst_box = {0, 0, 0, 0, 1, 1}; 406 407 assert(dpy); 408 assert(palette); 409 410 if (!subpicture) 411 return XvMCBadSubpicture; 412 413 subpicture_priv = subpicture->privData; 414 context_priv = subpicture_priv->context->privData; 415 pipe = context_priv->pipe; 416 417 dst_box.width = subpicture->num_palette_entries; 418 419 upload_sampler(pipe, subpicture_priv->palette, &dst_box, palette, 0, 0, 0); 420 421 XVMC_MSG(XVMC_TRACE, "[XvMC] Palette of Subpicture %p set.\n", subpicture); 422 423 return Success; 424} 425 426PUBLIC 427Status XvMCBlendSubpicture(Display *dpy, XvMCSurface *target_surface, XvMCSubpicture *subpicture, 428 short subx, short suby, unsigned short subw, unsigned short subh, 429 short surfx, short surfy, unsigned short surfw, unsigned short surfh) 430{ 431 struct u_rect src_rect = {subx, subx + subw, suby, suby + subh}; 432 struct u_rect dst_rect = {surfx, surfx + surfw, surfy, surfy + surfh}; 433 434 XvMCSurfacePrivate *surface_priv; 435 XvMCSubpicturePrivate *subpicture_priv; 436 437 XVMC_MSG(XVMC_TRACE, "[XvMC] Associating subpicture %p with surface %p.\n", subpicture, target_surface); 438 439 assert(dpy); 440 441 if (!target_surface) 442 return XvMCBadSurface; 443 444 if (!subpicture) 445 return XvMCBadSubpicture; 446 447 if (target_surface->context_id != subpicture->context_id) 448 return BadMatch; 449 450 /* TODO: Verify against subpicture independent scaling */ 451 452 surface_priv = target_surface->privData; 453 subpicture_priv = subpicture->privData; 454 455 /* TODO: Assert rects are within bounds? Or clip? */ 456 subpicture_priv->src_rect = src_rect; 457 subpicture_priv->dst_rect = dst_rect; 458 459 surface_priv->subpicture = subpicture; 460 subpicture_priv->surface = target_surface; 461 462 return Success; 463} 464 465PUBLIC 466Status XvMCBlendSubpicture2(Display *dpy, XvMCSurface *source_surface, XvMCSurface *target_surface, 467 XvMCSubpicture *subpicture, short subx, short suby, unsigned short subw, unsigned short subh, 468 short surfx, short surfy, unsigned short surfw, unsigned short surfh) 469{ 470 assert(dpy); 471 472 if (!source_surface || !target_surface) 473 return XvMCBadSurface; 474 475 if (!subpicture) 476 return XvMCBadSubpicture; 477 478 if (source_surface->context_id != subpicture->context_id) 479 return BadMatch; 480 481 if (source_surface->context_id != subpicture->context_id) 482 return BadMatch; 483 484 /* TODO: Assert rects are within bounds? Or clip? */ 485 486 return Success; 487} 488 489PUBLIC 490Status XvMCSyncSubpicture(Display *dpy, XvMCSubpicture *subpicture) 491{ 492 assert(dpy); 493 494 if (!subpicture) 495 return XvMCBadSubpicture; 496 497 return Success; 498} 499 500PUBLIC 501Status XvMCFlushSubpicture(Display *dpy, XvMCSubpicture *subpicture) 502{ 503 assert(dpy); 504 505 if (!subpicture) 506 return XvMCBadSubpicture; 507 508 return Success; 509} 510 511PUBLIC 512Status XvMCGetSubpictureStatus(Display *dpy, XvMCSubpicture *subpicture, int *status) 513{ 514 assert(dpy); 515 516 if (!subpicture) 517 return XvMCBadSubpicture; 518 519 assert(status); 520 521 /* TODO */ 522 *status = 0; 523 524 return Success; 525} 526