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_video_state.h" 36 #include "pipe/p_state.h" 37 38 #include "util/u_memory.h" 39 40 #include "vl/vl_csc.h" 41 #include "vl/vl_winsys.h" 42 43 #include "xvmc_private.h" 44 45 static Status Validate(Display *dpy, XvPortID port, int surface_type_id, 46 unsigned int width, unsigned int height, int flags, 47 bool *found_port, int *screen, int *chroma_format, 48 int *mc_type, int *surface_flags, 49 unsigned short *subpic_max_w, 50 unsigned short *subpic_max_h) 51 { 52 bool found_surface = false; 53 XvAdaptorInfo *adaptor_info; 54 unsigned int num_adaptors; 55 int num_types; 56 unsigned int max_width = 0, max_height = 0; 57 Status ret; 58 59 assert(dpy); 60 assert(found_port); 61 assert(screen); 62 assert(chroma_format); 63 assert(mc_type); 64 assert(surface_flags); 65 assert(subpic_max_w); 66 assert(subpic_max_h); 67 68 *found_port = false; 69 70 for (unsigned int i = 0; i < XScreenCount(dpy); ++i) { 71 ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info); 72 if (ret != Success) 73 return ret; 74 75 for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j) { 76 for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k) { 77 XvMCSurfaceInfo *surface_info; 78 79 if (adaptor_info[j].base_id + k != port) 80 continue; 81 82 *found_port = true; 83 84 surface_info = XvMCListSurfaceTypes(dpy, adaptor_info[j].base_id, &num_types); 85 if (!surface_info) { 86 XvFreeAdaptorInfo(adaptor_info); 87 return BadAlloc; 88 } 89 90 for (unsigned int l = 0; l < num_types && !found_surface; ++l) { 91 if (surface_info[l].surface_type_id != surface_type_id) 92 continue; 93 94 found_surface = true; 95 max_width = surface_info[l].max_width; 96 max_height = surface_info[l].max_height; 97 *chroma_format = surface_info[l].chroma_format; 98 *mc_type = surface_info[l].mc_type; 99 *surface_flags = surface_info[l].flags; 100 *subpic_max_w = surface_info[l].subpicture_max_width; 101 *subpic_max_h = surface_info[l].subpicture_max_height; 102 *screen = i; 103 104 XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested context surface format.\n" \ 105 "[XvMC] screen=%u, port=%u\n" \ 106 "[XvMC] id=0x%08X\n" \ 107 "[XvMC] max width=%u, max height=%u\n" \ 108 "[XvMC] chroma format=0x%08X\n" \ 109 "[XvMC] acceleration level=0x%08X\n" \ 110 "[XvMC] flags=0x%08X\n" \ 111 "[XvMC] subpicture max width=%u, max height=%u\n", 112 i, port, surface_type_id, max_width, max_height, *chroma_format, 113 *mc_type, *surface_flags, *subpic_max_w, *subpic_max_h); 114 } 115 116 XFree(surface_info); 117 } 118 } 119 120 XvFreeAdaptorInfo(adaptor_info); 121 } 122 123 if (!*found_port) { 124 XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable port.\n"); 125 return XvBadPort; 126 } 127 if (!found_surface) { 128 XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable surface.\n"); 129 return BadMatch; 130 } 131 if (width > max_width || height > max_height) { 132 XVMC_MSG(XVMC_ERR, "[XvMC] Requested context dimensions (w=%u,h=%u) too large (max w=%u,h=%u).\n", 133 width, height, max_width, max_height); 134 return BadValue; 135 } 136 if (flags != XVMC_DIRECT && flags != 0) { 137 XVMC_MSG(XVMC_ERR, "[XvMC] Invalid context flags 0x%08X.\n", flags); 138 return BadValue; 139 } 140 141 return Success; 142 } 143 144 static enum pipe_video_profile ProfileToPipe(int xvmc_profile) 145 { 146 if (xvmc_profile & XVMC_MPEG_1) 147 assert(0); 148 if (xvmc_profile & XVMC_MPEG_2) 149 return PIPE_VIDEO_PROFILE_MPEG2_MAIN; 150 if (xvmc_profile & XVMC_H263) 151 assert(0); 152 if (xvmc_profile & XVMC_MPEG_4) 153 assert(0); 154 155 assert(0); 156 157 XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized profile 0x%08X.\n", xvmc_profile); 158 159 return -1; 160 } 161 162 static enum pipe_video_chroma_format FormatToPipe(int xvmc_format) 163 { 164 switch (xvmc_format) { 165 case XVMC_CHROMA_FORMAT_420: 166 return PIPE_VIDEO_CHROMA_FORMAT_420; 167 case XVMC_CHROMA_FORMAT_422: 168 return PIPE_VIDEO_CHROMA_FORMAT_422; 169 case XVMC_CHROMA_FORMAT_444: 170 return PIPE_VIDEO_CHROMA_FORMAT_444; 171 default: 172 assert(0); 173 } 174 175 XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized format 0x%08X.\n", xvmc_format); 176 177 return -1; 178 } 179 180 PUBLIC 181 Status XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id, 182 int width, int height, int flags, XvMCContext *context) 183 { 184 bool found_port; 185 int scrn = 0; 186 int chroma_format = 0; 187 int mc_type = 0; 188 int surface_flags = 0; 189 unsigned short subpic_max_w = 0; 190 unsigned short subpic_max_h = 0; 191 Status ret; 192 struct vl_screen *vscreen; 193 struct pipe_context *pipe; 194 XvMCContextPrivate *context_priv; 195 vl_csc_matrix csc; 196 197 XVMC_MSG(XVMC_TRACE, "[XvMC] Creating context %p.\n", context); 198 199 assert(dpy); 200 201 if (!context) 202 return XvMCBadContext; 203 204 ret = Validate(dpy, port, surface_type_id, width, height, flags, 205 &found_port, &scrn, &chroma_format, &mc_type, &surface_flags, 206 &subpic_max_w, &subpic_max_h); 207 208 /* Success and XvBadPort have the same value */ 209 if (ret != Success || !found_port) 210 return ret; 211 212 /* XXX: Current limits */ 213 if (chroma_format != XVMC_CHROMA_FORMAT_420) { 214 XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsupported chroma format.\n"); 215 return BadImplementation; 216 } 217 if ((mc_type & ~XVMC_IDCT) != (XVMC_MOCOMP | XVMC_MPEG_2)) { 218 XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Non-MPEG2/Mocomp/iDCT acceleration unsupported.\n"); 219 return BadImplementation; 220 } 221 if (surface_flags & XVMC_INTRA_UNSIGNED) { 222 XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsigned intra unsupported.\n"); 223 return BadImplementation; 224 } 225 226 context_priv = CALLOC(1, sizeof(XvMCContextPrivate)); 227 if (!context_priv) 228 return BadAlloc; 229 230 /* TODO: Reuse screen if process creates another context */ 231 vscreen = vl_screen_create(dpy, scrn); 232 233 if (!vscreen) { 234 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL screen.\n"); 235 FREE(context_priv); 236 return BadAlloc; 237 } 238 239 pipe = vscreen->pscreen->context_create(vscreen->pscreen, vscreen); 240 if (!pipe) { 241 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL context.\n"); 242 vl_screen_destroy(vscreen); 243 FREE(context_priv); 244 return BadAlloc; 245 } 246 247 context_priv->decoder = pipe->create_video_decoder 248 ( 249 pipe, ProfileToPipe(mc_type), 250 (mc_type & XVMC_IDCT) ? PIPE_VIDEO_ENTRYPOINT_IDCT : PIPE_VIDEO_ENTRYPOINT_MC, 251 FormatToPipe(chroma_format), 252 width, height, 2, 253 true 254 ); 255 256 if (!context_priv->decoder) { 257 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL decoder.\n"); 258 pipe->destroy(pipe); 259 vl_screen_destroy(vscreen); 260 FREE(context_priv); 261 return BadAlloc; 262 } 263 264 if (!vl_compositor_init(&context_priv->compositor, pipe)) { 265 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor.\n"); 266 context_priv->decoder->destroy(context_priv->decoder); 267 pipe->destroy(pipe); 268 vl_screen_destroy(vscreen); 269 FREE(context_priv); 270 return BadAlloc; 271 } 272 273 if (!vl_compositor_init_state(&context_priv->cstate, pipe)) { 274 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor state.\n"); 275 vl_compositor_cleanup(&context_priv->compositor); 276 context_priv->decoder->destroy(context_priv->decoder); 277 pipe->destroy(pipe); 278 vl_screen_destroy(vscreen); 279 FREE(context_priv); 280 return BadAlloc; 281 } 282 283 284 context_priv->color_standard = 285 debug_get_bool_option("G3DVL_NO_CSC", FALSE) ? 286 VL_CSC_COLOR_STANDARD_IDENTITY : VL_CSC_COLOR_STANDARD_BT_601; 287 context_priv->procamp = vl_default_procamp; 288 289 vl_csc_get_matrix 290 ( 291 context_priv->color_standard, 292 &context_priv->procamp, true, &csc 293 ); 294 vl_compositor_set_csc_matrix(&context_priv->cstate, (const vl_csc_matrix *)&csc); 295 296 context_priv->vscreen = vscreen; 297 context_priv->pipe = pipe; 298 context_priv->subpicture_max_width = subpic_max_w; 299 context_priv->subpicture_max_height = subpic_max_h; 300 301 context->context_id = XAllocID(dpy); 302 context->surface_type_id = surface_type_id; 303 context->width = width; 304 context->height = height; 305 context->flags = flags; 306 context->port = port; 307 context->privData = context_priv; 308 309 SyncHandle(); 310 311 XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p created.\n", context); 312 313 return Success; 314 } 315 316 PUBLIC 317 Status XvMCDestroyContext(Display *dpy, XvMCContext *context) 318 { 319 XvMCContextPrivate *context_priv; 320 321 XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying context %p.\n", context); 322 323 assert(dpy); 324 325 if (!context || !context->privData) 326 return XvMCBadContext; 327 328 context_priv = context->privData; 329 context_priv->decoder->destroy(context_priv->decoder); 330 vl_compositor_cleanup_state(&context_priv->cstate); 331 vl_compositor_cleanup(&context_priv->compositor); 332 context_priv->pipe->destroy(context_priv->pipe); 333 vl_screen_destroy(context_priv->vscreen); 334 FREE(context_priv); 335 context->privData = NULL; 336 337 XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p destroyed.\n", context); 338 339 return Success; 340 } 341