1848b8605Smrg/************************************************************************** 2848b8605Smrg * 3848b8605Smrg * Copyright 2009 Younes Manton. 4848b8605Smrg * All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the 8848b8605Smrg * "Software"), to deal in the Software without restriction, including 9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish, 10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to 11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to 12848b8605Smrg * the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice (including the 15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions 16848b8605Smrg * of the Software. 17848b8605Smrg * 18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25848b8605Smrg * 26848b8605Smrg **************************************************************************/ 27848b8605Smrg 28848b8605Smrg#include <assert.h> 29848b8605Smrg 30848b8605Smrg#include <X11/Xlibint.h> 31848b8605Smrg#include <X11/extensions/XvMClib.h> 32848b8605Smrg 33848b8605Smrg#include "pipe/p_screen.h" 34848b8605Smrg#include "pipe/p_video_codec.h" 35848b8605Smrg#include "pipe/p_video_state.h" 36848b8605Smrg#include "pipe/p_state.h" 37848b8605Smrg 38848b8605Smrg#include "util/u_memory.h" 39848b8605Smrg 40848b8605Smrg#include "vl/vl_csc.h" 41848b8605Smrg#include "vl/vl_winsys.h" 42848b8605Smrg 43848b8605Smrg#include "xvmc_private.h" 44848b8605Smrg 45848b8605Smrgstatic Status Validate(Display *dpy, XvPortID port, int surface_type_id, 46848b8605Smrg unsigned int width, unsigned int height, int flags, 47848b8605Smrg bool *found_port, int *screen, int *chroma_format, 48848b8605Smrg int *mc_type, int *surface_flags, 49848b8605Smrg unsigned short *subpic_max_w, 50848b8605Smrg unsigned short *subpic_max_h) 51848b8605Smrg{ 52848b8605Smrg bool found_surface = false; 53848b8605Smrg XvAdaptorInfo *adaptor_info; 54848b8605Smrg unsigned int num_adaptors; 55848b8605Smrg int num_types; 56848b8605Smrg unsigned int max_width = 0, max_height = 0; 57848b8605Smrg Status ret; 58848b8605Smrg 59848b8605Smrg assert(dpy); 60848b8605Smrg assert(found_port); 61848b8605Smrg assert(screen); 62848b8605Smrg assert(chroma_format); 63848b8605Smrg assert(mc_type); 64848b8605Smrg assert(surface_flags); 65848b8605Smrg assert(subpic_max_w); 66848b8605Smrg assert(subpic_max_h); 67848b8605Smrg 68848b8605Smrg *found_port = false; 69848b8605Smrg 70b8e80941Smrg for (int i = 0; i < XScreenCount(dpy); ++i) { 71848b8605Smrg ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info); 72848b8605Smrg if (ret != Success) 73848b8605Smrg return ret; 74848b8605Smrg 75848b8605Smrg for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j) { 76848b8605Smrg for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k) { 77848b8605Smrg XvMCSurfaceInfo *surface_info; 78848b8605Smrg 79848b8605Smrg if (adaptor_info[j].base_id + k != port) 80848b8605Smrg continue; 81848b8605Smrg 82848b8605Smrg *found_port = true; 83848b8605Smrg 84848b8605Smrg surface_info = XvMCListSurfaceTypes(dpy, adaptor_info[j].base_id, &num_types); 85848b8605Smrg if (!surface_info) { 86848b8605Smrg XvFreeAdaptorInfo(adaptor_info); 87848b8605Smrg return BadAlloc; 88848b8605Smrg } 89848b8605Smrg 90b8e80941Smrg for (int l = 0; l < num_types && !found_surface; ++l) { 91848b8605Smrg if (surface_info[l].surface_type_id != surface_type_id) 92848b8605Smrg continue; 93848b8605Smrg 94848b8605Smrg found_surface = true; 95848b8605Smrg max_width = surface_info[l].max_width; 96848b8605Smrg max_height = surface_info[l].max_height; 97848b8605Smrg *chroma_format = surface_info[l].chroma_format; 98848b8605Smrg *mc_type = surface_info[l].mc_type; 99848b8605Smrg *surface_flags = surface_info[l].flags; 100848b8605Smrg *subpic_max_w = surface_info[l].subpicture_max_width; 101848b8605Smrg *subpic_max_h = surface_info[l].subpicture_max_height; 102848b8605Smrg *screen = i; 103848b8605Smrg 104848b8605Smrg XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested context surface format.\n" \ 105848b8605Smrg "[XvMC] screen=%u, port=%u\n" \ 106848b8605Smrg "[XvMC] id=0x%08X\n" \ 107848b8605Smrg "[XvMC] max width=%u, max height=%u\n" \ 108848b8605Smrg "[XvMC] chroma format=0x%08X\n" \ 109848b8605Smrg "[XvMC] acceleration level=0x%08X\n" \ 110848b8605Smrg "[XvMC] flags=0x%08X\n" \ 111848b8605Smrg "[XvMC] subpicture max width=%u, max height=%u\n", 112848b8605Smrg i, port, surface_type_id, max_width, max_height, *chroma_format, 113848b8605Smrg *mc_type, *surface_flags, *subpic_max_w, *subpic_max_h); 114848b8605Smrg } 115848b8605Smrg 116848b8605Smrg free(surface_info); 117848b8605Smrg } 118848b8605Smrg } 119848b8605Smrg 120848b8605Smrg XvFreeAdaptorInfo(adaptor_info); 121848b8605Smrg } 122848b8605Smrg 123848b8605Smrg if (!*found_port) { 124848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable port.\n"); 125848b8605Smrg return XvBadPort; 126848b8605Smrg } 127848b8605Smrg if (!found_surface) { 128848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable surface.\n"); 129848b8605Smrg return BadMatch; 130848b8605Smrg } 131848b8605Smrg if (width > max_width || height > max_height) { 132848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Requested context dimensions (w=%u,h=%u) too large (max w=%u,h=%u).\n", 133848b8605Smrg width, height, max_width, max_height); 134848b8605Smrg return BadValue; 135848b8605Smrg } 136848b8605Smrg if (flags != XVMC_DIRECT && flags != 0) { 137848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Invalid context flags 0x%08X.\n", flags); 138848b8605Smrg return BadValue; 139848b8605Smrg } 140848b8605Smrg 141848b8605Smrg return Success; 142848b8605Smrg} 143848b8605Smrg 144848b8605Smrgstatic enum pipe_video_profile ProfileToPipe(int xvmc_profile) 145848b8605Smrg{ 146848b8605Smrg if (xvmc_profile & XVMC_MPEG_1) 147848b8605Smrg assert(0); 148848b8605Smrg if (xvmc_profile & XVMC_MPEG_2) 149848b8605Smrg return PIPE_VIDEO_PROFILE_MPEG2_MAIN; 150848b8605Smrg if (xvmc_profile & XVMC_H263) 151848b8605Smrg assert(0); 152848b8605Smrg if (xvmc_profile & XVMC_MPEG_4) 153848b8605Smrg assert(0); 154848b8605Smrg 155848b8605Smrg assert(0); 156848b8605Smrg 157848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized profile 0x%08X.\n", xvmc_profile); 158848b8605Smrg 159848b8605Smrg return -1; 160848b8605Smrg} 161848b8605Smrg 162848b8605Smrgstatic enum pipe_video_chroma_format FormatToPipe(int xvmc_format) 163848b8605Smrg{ 164848b8605Smrg switch (xvmc_format) { 165848b8605Smrg case XVMC_CHROMA_FORMAT_420: 166848b8605Smrg return PIPE_VIDEO_CHROMA_FORMAT_420; 167848b8605Smrg case XVMC_CHROMA_FORMAT_422: 168848b8605Smrg return PIPE_VIDEO_CHROMA_FORMAT_422; 169848b8605Smrg case XVMC_CHROMA_FORMAT_444: 170848b8605Smrg return PIPE_VIDEO_CHROMA_FORMAT_444; 171848b8605Smrg default: 172848b8605Smrg assert(0); 173848b8605Smrg } 174848b8605Smrg 175848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized format 0x%08X.\n", xvmc_format); 176848b8605Smrg 177848b8605Smrg return -1; 178848b8605Smrg} 179848b8605Smrg 180848b8605SmrgPUBLIC 181848b8605SmrgStatus XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id, 182848b8605Smrg int width, int height, int flags, XvMCContext *context) 183848b8605Smrg{ 184848b8605Smrg bool found_port; 185848b8605Smrg int scrn = 0; 186848b8605Smrg int chroma_format = 0; 187848b8605Smrg int mc_type = 0; 188848b8605Smrg int surface_flags = 0; 189848b8605Smrg unsigned short subpic_max_w = 0; 190848b8605Smrg unsigned short subpic_max_h = 0; 191848b8605Smrg Status ret; 192848b8605Smrg struct vl_screen *vscreen; 193848b8605Smrg struct pipe_context *pipe; 194b8e80941Smrg struct pipe_video_codec templat = {0}; 195848b8605Smrg XvMCContextPrivate *context_priv; 196848b8605Smrg vl_csc_matrix csc; 197848b8605Smrg 198848b8605Smrg XVMC_MSG(XVMC_TRACE, "[XvMC] Creating context %p.\n", context); 199848b8605Smrg 200848b8605Smrg assert(dpy); 201848b8605Smrg 202848b8605Smrg if (!context) 203848b8605Smrg return XvMCBadContext; 204848b8605Smrg 205848b8605Smrg ret = Validate(dpy, port, surface_type_id, width, height, flags, 206848b8605Smrg &found_port, &scrn, &chroma_format, &mc_type, &surface_flags, 207848b8605Smrg &subpic_max_w, &subpic_max_h); 208848b8605Smrg 209848b8605Smrg /* Success and XvBadPort have the same value */ 210848b8605Smrg if (ret != Success || !found_port) 211848b8605Smrg return ret; 212848b8605Smrg 213848b8605Smrg /* XXX: Current limits */ 214848b8605Smrg if (chroma_format != XVMC_CHROMA_FORMAT_420) { 215848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsupported chroma format.\n"); 216848b8605Smrg return BadImplementation; 217848b8605Smrg } 218848b8605Smrg if ((mc_type & ~XVMC_IDCT) != (XVMC_MOCOMP | XVMC_MPEG_2)) { 219848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Non-MPEG2/Mocomp/iDCT acceleration unsupported.\n"); 220848b8605Smrg return BadImplementation; 221848b8605Smrg } 222848b8605Smrg if (surface_flags & XVMC_INTRA_UNSIGNED) { 223848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsigned intra unsupported.\n"); 224848b8605Smrg return BadImplementation; 225848b8605Smrg } 226848b8605Smrg 227848b8605Smrg context_priv = CALLOC(1, sizeof(XvMCContextPrivate)); 228848b8605Smrg if (!context_priv) 229848b8605Smrg return BadAlloc; 230848b8605Smrg 231848b8605Smrg /* TODO: Reuse screen if process creates another context */ 232b8e80941Smrg vscreen = vl_dri3_screen_create(dpy, scrn); 233b8e80941Smrg if (!vscreen) 234b8e80941Smrg vscreen = vl_dri2_screen_create(dpy, scrn); 235848b8605Smrg 236848b8605Smrg if (!vscreen) { 237848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL screen.\n"); 238848b8605Smrg FREE(context_priv); 239848b8605Smrg return BadAlloc; 240848b8605Smrg } 241848b8605Smrg 242b8e80941Smrg pipe = vscreen->pscreen->context_create(vscreen->pscreen, NULL, 0); 243848b8605Smrg if (!pipe) { 244848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL context.\n"); 245b8e80941Smrg vscreen->destroy(vscreen); 246848b8605Smrg FREE(context_priv); 247848b8605Smrg return BadAlloc; 248848b8605Smrg } 249848b8605Smrg 250848b8605Smrg templat.profile = ProfileToPipe(mc_type); 251848b8605Smrg templat.entrypoint = (mc_type & XVMC_IDCT) ? PIPE_VIDEO_ENTRYPOINT_IDCT : PIPE_VIDEO_ENTRYPOINT_MC; 252848b8605Smrg templat.chroma_format = FormatToPipe(chroma_format); 253848b8605Smrg templat.width = width; 254848b8605Smrg templat.height = height; 255848b8605Smrg templat.max_references = 2; 256848b8605Smrg templat.expect_chunked_decode = true; 257848b8605Smrg 258848b8605Smrg context_priv->decoder = pipe->create_video_codec(pipe, &templat); 259848b8605Smrg 260848b8605Smrg if (!context_priv->decoder) { 261848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL decoder.\n"); 262848b8605Smrg pipe->destroy(pipe); 263b8e80941Smrg vscreen->destroy(vscreen); 264848b8605Smrg FREE(context_priv); 265848b8605Smrg return BadAlloc; 266848b8605Smrg } 267848b8605Smrg 268848b8605Smrg if (!vl_compositor_init(&context_priv->compositor, pipe)) { 269848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor.\n"); 270848b8605Smrg context_priv->decoder->destroy(context_priv->decoder); 271848b8605Smrg pipe->destroy(pipe); 272b8e80941Smrg vscreen->destroy(vscreen); 273848b8605Smrg FREE(context_priv); 274848b8605Smrg return BadAlloc; 275848b8605Smrg } 276848b8605Smrg 277848b8605Smrg if (!vl_compositor_init_state(&context_priv->cstate, pipe)) { 278848b8605Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor state.\n"); 279848b8605Smrg vl_compositor_cleanup(&context_priv->compositor); 280848b8605Smrg context_priv->decoder->destroy(context_priv->decoder); 281848b8605Smrg pipe->destroy(pipe); 282b8e80941Smrg vscreen->destroy(vscreen); 283848b8605Smrg FREE(context_priv); 284848b8605Smrg return BadAlloc; 285848b8605Smrg } 286848b8605Smrg 287848b8605Smrg 288848b8605Smrg context_priv->color_standard = 289848b8605Smrg debug_get_bool_option("G3DVL_NO_CSC", FALSE) ? 290848b8605Smrg VL_CSC_COLOR_STANDARD_IDENTITY : VL_CSC_COLOR_STANDARD_BT_601; 291848b8605Smrg context_priv->procamp = vl_default_procamp; 292848b8605Smrg 293848b8605Smrg vl_csc_get_matrix 294848b8605Smrg ( 295848b8605Smrg context_priv->color_standard, 296848b8605Smrg &context_priv->procamp, true, &csc 297848b8605Smrg ); 298b8e80941Smrg vl_compositor_set_csc_matrix(&context_priv->cstate, (const vl_csc_matrix *)&csc, 1.0f, 0.0f); 299848b8605Smrg 300848b8605Smrg context_priv->vscreen = vscreen; 301848b8605Smrg context_priv->pipe = pipe; 302848b8605Smrg context_priv->subpicture_max_width = subpic_max_w; 303848b8605Smrg context_priv->subpicture_max_height = subpic_max_h; 304848b8605Smrg 305848b8605Smrg context->context_id = XAllocID(dpy); 306848b8605Smrg context->surface_type_id = surface_type_id; 307848b8605Smrg context->width = width; 308848b8605Smrg context->height = height; 309848b8605Smrg context->flags = flags; 310848b8605Smrg context->port = port; 311848b8605Smrg context->privData = context_priv; 312848b8605Smrg 313848b8605Smrg SyncHandle(); 314848b8605Smrg 315848b8605Smrg XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p created.\n", context); 316848b8605Smrg 317848b8605Smrg return Success; 318848b8605Smrg} 319848b8605Smrg 320848b8605SmrgPUBLIC 321848b8605SmrgStatus XvMCDestroyContext(Display *dpy, XvMCContext *context) 322848b8605Smrg{ 323848b8605Smrg XvMCContextPrivate *context_priv; 324848b8605Smrg 325848b8605Smrg XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying context %p.\n", context); 326848b8605Smrg 327848b8605Smrg assert(dpy); 328848b8605Smrg 329848b8605Smrg if (!context || !context->privData) 330848b8605Smrg return XvMCBadContext; 331848b8605Smrg 332848b8605Smrg context_priv = context->privData; 333848b8605Smrg context_priv->decoder->destroy(context_priv->decoder); 334848b8605Smrg vl_compositor_cleanup_state(&context_priv->cstate); 335848b8605Smrg vl_compositor_cleanup(&context_priv->compositor); 336848b8605Smrg context_priv->pipe->destroy(context_priv->pipe); 337b8e80941Smrg context_priv->vscreen->destroy(context_priv->vscreen); 338848b8605Smrg FREE(context_priv); 339848b8605Smrg context->privData = NULL; 340848b8605Smrg 341848b8605Smrg XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p destroyed.\n", context); 342848b8605Smrg 343848b8605Smrg return Success; 344848b8605Smrg} 345