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_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 (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 (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 free(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 struct pipe_video_codec templat = {0}; 195 XvMCContextPrivate *context_priv; 196 vl_csc_matrix csc; 197 198 XVMC_MSG(XVMC_TRACE, "[XvMC] Creating context %p.\n", context); 199 200 assert(dpy); 201 202 if (!context) 203 return XvMCBadContext; 204 205 ret = Validate(dpy, port, surface_type_id, width, height, flags, 206 &found_port, &scrn, &chroma_format, &mc_type, &surface_flags, 207 &subpic_max_w, &subpic_max_h); 208 209 /* Success and XvBadPort have the same value */ 210 if (ret != Success || !found_port) 211 return ret; 212 213 /* XXX: Current limits */ 214 if (chroma_format != XVMC_CHROMA_FORMAT_420) { 215 XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsupported chroma format.\n"); 216 return BadImplementation; 217 } 218 if ((mc_type & ~XVMC_IDCT) != (XVMC_MOCOMP | XVMC_MPEG_2)) { 219 XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Non-MPEG2/Mocomp/iDCT acceleration unsupported.\n"); 220 return BadImplementation; 221 } 222 if (surface_flags & XVMC_INTRA_UNSIGNED) { 223 XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsigned intra unsupported.\n"); 224 return BadImplementation; 225 } 226 227 context_priv = CALLOC(1, sizeof(XvMCContextPrivate)); 228 if (!context_priv) 229 return BadAlloc; 230 231 /* TODO: Reuse screen if process creates another context */ 232 vscreen = vl_dri2_screen_create(dpy, scrn); 233 234 if (!vscreen) { 235 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL screen.\n"); 236 FREE(context_priv); 237 return BadAlloc; 238 } 239 240 pipe = vscreen->pscreen->context_create(vscreen->pscreen, vscreen, 0); 241 if (!pipe) { 242 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL context.\n"); 243 vscreen->destroy(vscreen); 244 FREE(context_priv); 245 return BadAlloc; 246 } 247 248 templat.profile = ProfileToPipe(mc_type); 249 templat.entrypoint = (mc_type & XVMC_IDCT) ? PIPE_VIDEO_ENTRYPOINT_IDCT : PIPE_VIDEO_ENTRYPOINT_MC; 250 templat.chroma_format = FormatToPipe(chroma_format); 251 templat.width = width; 252 templat.height = height; 253 templat.max_references = 2; 254 templat.expect_chunked_decode = true; 255 256 context_priv->decoder = pipe->create_video_codec(pipe, &templat); 257 258 if (!context_priv->decoder) { 259 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL decoder.\n"); 260 pipe->destroy(pipe); 261 vscreen->destroy(vscreen); 262 FREE(context_priv); 263 return BadAlloc; 264 } 265 266 if (!vl_compositor_init(&context_priv->compositor, pipe)) { 267 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor.\n"); 268 context_priv->decoder->destroy(context_priv->decoder); 269 pipe->destroy(pipe); 270 vscreen->destroy(vscreen); 271 FREE(context_priv); 272 return BadAlloc; 273 } 274 275 if (!vl_compositor_init_state(&context_priv->cstate, pipe)) { 276 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor state.\n"); 277 vl_compositor_cleanup(&context_priv->compositor); 278 context_priv->decoder->destroy(context_priv->decoder); 279 pipe->destroy(pipe); 280 vscreen->destroy(vscreen); 281 FREE(context_priv); 282 return BadAlloc; 283 } 284 285 286 context_priv->color_standard = 287 debug_get_bool_option("G3DVL_NO_CSC", FALSE) ? 288 VL_CSC_COLOR_STANDARD_IDENTITY : VL_CSC_COLOR_STANDARD_BT_601; 289 context_priv->procamp = vl_default_procamp; 290 291 vl_csc_get_matrix 292 ( 293 context_priv->color_standard, 294 &context_priv->procamp, true, &csc 295 ); 296 vl_compositor_set_csc_matrix(&context_priv->cstate, (const vl_csc_matrix *)&csc, 1.0f, 0.0f); 297 298 context_priv->vscreen = vscreen; 299 context_priv->pipe = pipe; 300 context_priv->subpicture_max_width = subpic_max_w; 301 context_priv->subpicture_max_height = subpic_max_h; 302 303 context->context_id = XAllocID(dpy); 304 context->surface_type_id = surface_type_id; 305 context->width = width; 306 context->height = height; 307 context->flags = flags; 308 context->port = port; 309 context->privData = context_priv; 310 311 SyncHandle(); 312 313 XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p created.\n", context); 314 315 return Success; 316 } 317 318 PUBLIC 319 Status XvMCDestroyContext(Display *dpy, XvMCContext *context) 320 { 321 XvMCContextPrivate *context_priv; 322 323 XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying context %p.\n", context); 324 325 assert(dpy); 326 327 if (!context || !context->privData) 328 return XvMCBadContext; 329 330 context_priv = context->privData; 331 context_priv->decoder->destroy(context_priv->decoder); 332 vl_compositor_cleanup_state(&context_priv->cstate); 333 vl_compositor_cleanup(&context_priv->compositor); 334 context_priv->pipe->destroy(context_priv->pipe); 335 context_priv->vscreen->destroy(context_priv->vscreen); 336 FREE(context_priv); 337 context->privData = NULL; 338 339 XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p destroyed.\n", context); 340 341 return Success; 342 } 343