1 /**************************************************************************
3 * Copyright 2009 Younes Manton.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
30 #include <X11/Xlibint.h>
31 #include <X11/extensions/XvMClib.h>
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"
38 #include "util/u_memory.h"
40 #include "vl/vl_csc.h"
41 #include "vl/vl_winsys.h"
43 #include "xvmc_private.h"
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
)
52 bool found_surface
= false;
53 XvAdaptorInfo
*adaptor_info
;
54 unsigned int num_adaptors
;
56 unsigned int max_width
= 0, max_height
= 0;
62 assert(chroma_format
);
64 assert(surface_flags
);
70 for (int i
= 0; i
< XScreenCount(dpy
); ++i
) {
71 ret
= XvQueryAdaptors(dpy
, XRootWindow(dpy
, i
), &num_adaptors
, &adaptor_info
);
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
;
79 if (adaptor_info
[j
].base_id
+ k
!= port
)
84 surface_info
= XvMCListSurfaceTypes(dpy
, adaptor_info
[j
].base_id
, &num_types
);
86 XvFreeAdaptorInfo(adaptor_info
);
90 for (int l
= 0; l
< num_types
&& !found_surface
; ++l
) {
91 if (surface_info
[l
].surface_type_id
!= surface_type_id
)
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
;
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
);
120 XvFreeAdaptorInfo(adaptor_info
);
124 XVMC_MSG(XVMC_ERR
, "[XvMC] Could not find a suitable port.\n");
127 if (!found_surface
) {
128 XVMC_MSG(XVMC_ERR
, "[XvMC] Could not find a suitable surface.\n");
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
);
136 if (flags
!= XVMC_DIRECT
&& flags
!= 0) {
137 XVMC_MSG(XVMC_ERR
, "[XvMC] Invalid context flags 0x%08X.\n", flags
);
144 static enum pipe_video_profile
ProfileToPipe(int xvmc_profile
)
146 if (xvmc_profile
& XVMC_MPEG_1
)
148 if (xvmc_profile
& XVMC_MPEG_2
)
149 return PIPE_VIDEO_PROFILE_MPEG2_MAIN
;
150 if (xvmc_profile
& XVMC_H263
)
152 if (xvmc_profile
& XVMC_MPEG_4
)
157 XVMC_MSG(XVMC_ERR
, "[XvMC] Unrecognized profile 0x%08X.\n", xvmc_profile
);
162 static enum pipe_video_chroma_format
FormatToPipe(int xvmc_format
)
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
;
175 XVMC_MSG(XVMC_ERR
, "[XvMC] Unrecognized format 0x%08X.\n", xvmc_format
);
181 Status
XvMCCreateContext(Display
*dpy
, XvPortID port
, int surface_type_id
,
182 int width
, int height
, int flags
, XvMCContext
*context
)
186 int chroma_format
= 0;
188 int surface_flags
= 0;
189 unsigned short subpic_max_w
= 0;
190 unsigned short subpic_max_h
= 0;
192 struct vl_screen
*vscreen
;
193 struct pipe_context
*pipe
;
194 struct pipe_video_codec templat
= {0};
195 XvMCContextPrivate
*context_priv
;
198 XVMC_MSG(XVMC_TRACE
, "[XvMC] Creating context %p.\n", context
);
203 return XvMCBadContext
;
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
);
209 /* Success and XvBadPort have the same value */
210 if (ret
!= Success
|| !found_port
)
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
;
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
;
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
;
227 context_priv
= CALLOC(1, sizeof(XvMCContextPrivate
));
231 /* TODO: Reuse screen if process creates another context */
232 vscreen
= vl_dri3_screen_create(dpy
, scrn
);
234 vscreen
= vl_dri2_screen_create(dpy
, scrn
);
237 XVMC_MSG(XVMC_ERR
, "[XvMC] Could not create VL screen.\n");
242 pipe
= vscreen
->pscreen
->context_create(vscreen
->pscreen
, NULL
, 0);
244 XVMC_MSG(XVMC_ERR
, "[XvMC] Could not create VL context.\n");
245 vscreen
->destroy(vscreen
);
250 templat
.profile
= ProfileToPipe(mc_type
);
251 templat
.entrypoint
= (mc_type
& XVMC_IDCT
) ? PIPE_VIDEO_ENTRYPOINT_IDCT
: PIPE_VIDEO_ENTRYPOINT_MC
;
252 templat
.chroma_format
= FormatToPipe(chroma_format
);
253 templat
.width
= width
;
254 templat
.height
= height
;
255 templat
.max_references
= 2;
256 templat
.expect_chunked_decode
= true;
258 context_priv
->decoder
= pipe
->create_video_codec(pipe
, &templat
);
260 if (!context_priv
->decoder
) {
261 XVMC_MSG(XVMC_ERR
, "[XvMC] Could not create VL decoder.\n");
263 vscreen
->destroy(vscreen
);
268 if (!vl_compositor_init(&context_priv
->compositor
, pipe
)) {
269 XVMC_MSG(XVMC_ERR
, "[XvMC] Could not create VL compositor.\n");
270 context_priv
->decoder
->destroy(context_priv
->decoder
);
272 vscreen
->destroy(vscreen
);
277 if (!vl_compositor_init_state(&context_priv
->cstate
, pipe
)) {
278 XVMC_MSG(XVMC_ERR
, "[XvMC] Could not create VL compositor state.\n");
279 vl_compositor_cleanup(&context_priv
->compositor
);
280 context_priv
->decoder
->destroy(context_priv
->decoder
);
282 vscreen
->destroy(vscreen
);
288 context_priv
->color_standard
=
289 debug_get_bool_option("G3DVL_NO_CSC", FALSE
) ?
290 VL_CSC_COLOR_STANDARD_IDENTITY
: VL_CSC_COLOR_STANDARD_BT_601
;
291 context_priv
->procamp
= vl_default_procamp
;
295 context_priv
->color_standard
,
296 &context_priv
->procamp
, true, &csc
298 vl_compositor_set_csc_matrix(&context_priv
->cstate
, (const vl_csc_matrix
*)&csc
, 1.0f
, 0.0f
);
300 context_priv
->vscreen
= vscreen
;
301 context_priv
->pipe
= pipe
;
302 context_priv
->subpicture_max_width
= subpic_max_w
;
303 context_priv
->subpicture_max_height
= subpic_max_h
;
305 context
->context_id
= XAllocID(dpy
);
306 context
->surface_type_id
= surface_type_id
;
307 context
->width
= width
;
308 context
->height
= height
;
309 context
->flags
= flags
;
310 context
->port
= port
;
311 context
->privData
= context_priv
;
315 XVMC_MSG(XVMC_TRACE
, "[XvMC] Context %p created.\n", context
);
321 Status
XvMCDestroyContext(Display
*dpy
, XvMCContext
*context
)
323 XvMCContextPrivate
*context_priv
;
325 XVMC_MSG(XVMC_TRACE
, "[XvMC] Destroying context %p.\n", context
);
329 if (!context
|| !context
->privData
)
330 return XvMCBadContext
;
332 context_priv
= context
->privData
;
333 context_priv
->decoder
->destroy(context_priv
->decoder
);
334 vl_compositor_cleanup_state(&context_priv
->cstate
);
335 vl_compositor_cleanup(&context_priv
->compositor
);
336 context_priv
->pipe
->destroy(context_priv
->pipe
);
337 context_priv
->vscreen
->destroy(context_priv
->vscreen
);
339 context
->privData
= NULL
;
341 XVMC_MSG(XVMC_TRACE
, "[XvMC] Context %p destroyed.\n", context
);