Merge branch 'master' of ssh://git.freedesktop.org/git/mesa/mesa into pipe-video
[mesa.git] / src / gallium / state_trackers / xorg / xvmc / context.c
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 #include <X11/Xlibint.h>
30 #include <X11/extensions/XvMClib.h>
31 #include <pipe/p_screen.h>
32 #include <pipe/p_video_context.h>
33 #include <pipe/p_video_state.h>
34 #include <pipe/p_state.h>
35 #include <vl_winsys.h>
36 #include <util/u_memory.h>
37 #include <vl/vl_csc.h>
38 #include "xvmc_private.h"
39
40 static Status Validate(Display *dpy, XvPortID port, int surface_type_id,
41 unsigned int width, unsigned int height, int flags,
42 bool *found_port, int *screen, int *chroma_format,
43 int *mc_type, int *surface_flags,
44 unsigned short *subpic_max_w,
45 unsigned short *subpic_max_h)
46 {
47 bool found_surface = false;
48 XvAdaptorInfo *adaptor_info;
49 unsigned int num_adaptors;
50 int num_types;
51 unsigned int max_width, max_height;
52 Status ret;
53
54 assert(dpy);
55 assert(found_port);
56 assert(screen);
57 assert(chroma_format);
58 assert(mc_type);
59 assert(surface_flags);
60 assert(subpic_max_w);
61 assert(subpic_max_h);
62
63 *found_port = false;
64
65 for (unsigned int i = 0; i < XScreenCount(dpy); ++i) {
66 ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info);
67 if (ret != Success)
68 return ret;
69
70 for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j) {
71 for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k) {
72 XvMCSurfaceInfo *surface_info;
73
74 if (adaptor_info[j].base_id + k != port)
75 continue;
76
77 *found_port = true;
78
79 surface_info = XvMCListSurfaceTypes(dpy, adaptor_info[j].base_id, &num_types);
80 if (!surface_info) {
81 XvFreeAdaptorInfo(adaptor_info);
82 return BadAlloc;
83 }
84
85 for (unsigned int l = 0; l < num_types && !found_surface; ++l) {
86 if (surface_info[l].surface_type_id != surface_type_id)
87 continue;
88
89 found_surface = true;
90 max_width = surface_info[l].max_width;
91 max_height = surface_info[l].max_height;
92 *chroma_format = surface_info[l].chroma_format;
93 *mc_type = surface_info[l].mc_type;
94 *surface_flags = surface_info[l].flags;
95 *subpic_max_w = surface_info[l].subpicture_max_width;
96 *subpic_max_h = surface_info[l].subpicture_max_height;
97 *screen = i;
98
99 XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested context surface format.\n" \
100 "[XvMC] screen=%u, port=%u\n" \
101 "[XvMC] id=0x%08X\n" \
102 "[XvMC] max width=%u, max height=%u\n" \
103 "[XvMC] chroma format=0x%08X\n" \
104 "[XvMC] acceleration level=0x%08X\n" \
105 "[XvMC] flags=0x%08X\n" \
106 "[XvMC] subpicture max width=%u, max height=%u\n",
107 i, port, surface_type_id, max_width, max_height, *chroma_format,
108 *mc_type, *surface_flags, *subpic_max_w, *subpic_max_h);
109 }
110
111 XFree(surface_info);
112 }
113 }
114
115 XvFreeAdaptorInfo(adaptor_info);
116 }
117
118 if (!*found_port) {
119 XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable port.\n");
120 return XvBadPort;
121 }
122 if (!found_surface) {
123 XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable surface.\n");
124 return BadMatch;
125 }
126 if (width > max_width || height > max_height) {
127 XVMC_MSG(XVMC_ERR, "[XvMC] Requested context dimensions (w=%u,h=%u) too large (max w=%u,h=%u).\n",
128 width, height, max_width, max_height);
129 return BadValue;
130 }
131 if (flags != XVMC_DIRECT && flags != 0) {
132 XVMC_MSG(XVMC_ERR, "[XvMC] Invalid context flags 0x%08X.\n", flags);
133 return BadValue;
134 }
135
136 return Success;
137 }
138
139 static enum pipe_video_profile ProfileToPipe(int xvmc_profile)
140 {
141 if (xvmc_profile & XVMC_MPEG_1)
142 assert(0);
143 if (xvmc_profile & XVMC_MPEG_2)
144 return PIPE_VIDEO_PROFILE_MPEG2_MAIN;
145 if (xvmc_profile & XVMC_H263)
146 assert(0);
147 if (xvmc_profile & XVMC_MPEG_4)
148 assert(0);
149
150 assert(0);
151
152 XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized profile 0x%08X.\n", xvmc_profile);
153
154 return -1;
155 }
156
157 static enum pipe_video_chroma_format FormatToPipe(int xvmc_format)
158 {
159 switch (xvmc_format) {
160 case XVMC_CHROMA_FORMAT_420:
161 return PIPE_VIDEO_CHROMA_FORMAT_420;
162 case XVMC_CHROMA_FORMAT_422:
163 return PIPE_VIDEO_CHROMA_FORMAT_422;
164 case XVMC_CHROMA_FORMAT_444:
165 return PIPE_VIDEO_CHROMA_FORMAT_444;
166 default:
167 assert(0);
168 }
169
170 XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized format 0x%08X.\n", xvmc_format);
171
172 return -1;
173 }
174
175 PUBLIC
176 Status XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id,
177 int width, int height, int flags, XvMCContext *context)
178 {
179 bool found_port;
180 int scrn;
181 int chroma_format;
182 int mc_type;
183 int surface_flags;
184 unsigned short subpic_max_w;
185 unsigned short subpic_max_h;
186 Status ret;
187 struct vl_screen *vscreen;
188 struct vl_context *vctx;
189 XvMCContextPrivate *context_priv;
190 float csc[16];
191
192 XVMC_MSG(XVMC_TRACE, "[XvMC] Creating context %p.\n", context);
193
194 assert(dpy);
195
196 if (!context)
197 return XvMCBadContext;
198
199 ret = Validate(dpy, port, surface_type_id, width, height, flags,
200 &found_port, &scrn, &chroma_format, &mc_type, &surface_flags,
201 &subpic_max_w, &subpic_max_h);
202
203 /* Success and XvBadPort have the same value */
204 if (ret != Success || !found_port)
205 return ret;
206
207 /* XXX: Current limits */
208 if (chroma_format != XVMC_CHROMA_FORMAT_420) {
209 XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsupported chroma format.\n");
210 return BadImplementation;
211 }
212 if (mc_type != (XVMC_MOCOMP | XVMC_MPEG_2)) {
213 XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Non-MPEG2/Mocomp acceleration unsupported.\n");
214 return BadImplementation;
215 }
216 if (!(surface_flags & XVMC_INTRA_UNSIGNED)) {
217 XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Signed intra unsupported.\n");
218 return BadImplementation;
219 }
220
221 context_priv = CALLOC(1, sizeof(XvMCContextPrivate));
222 if (!context_priv)
223 return BadAlloc;
224
225 /* TODO: Reuse screen if process creates another context */
226 vscreen = vl_screen_create(dpy, scrn);
227
228 if (!vscreen) {
229 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL screen.\n");
230 FREE(context_priv);
231 return BadAlloc;
232 }
233
234 vctx = vl_video_create(vscreen, ProfileToPipe(mc_type),
235 FormatToPipe(chroma_format), width, height);
236
237 if (!vctx) {
238 XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL context.\n");
239 vl_screen_destroy(vscreen);
240 FREE(context_priv);
241 return BadAlloc;
242 }
243
244 /* TODO: Define some Xv attribs to allow users to specify color standard, procamp */
245 vl_csc_get_matrix
246 (
247 debug_get_bool_option("G3DVL_NO_CSC", FALSE) ?
248 VL_CSC_COLOR_STANDARD_IDENTITY : VL_CSC_COLOR_STANDARD_BT_601,
249 NULL, true, csc
250 );
251 vctx->vpipe->set_csc_matrix(vctx->vpipe, csc);
252
253 context_priv->vctx = vctx;
254 context_priv->subpicture_max_width = subpic_max_w;
255 context_priv->subpicture_max_height = subpic_max_h;
256
257 context->context_id = XAllocID(dpy);
258 context->surface_type_id = surface_type_id;
259 context->width = width;
260 context->height = height;
261 context->flags = flags;
262 context->port = port;
263 context->privData = context_priv;
264
265 SyncHandle();
266
267 XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p created.\n", context);
268
269 return Success;
270 }
271
272 PUBLIC
273 Status XvMCDestroyContext(Display *dpy, XvMCContext *context)
274 {
275 struct vl_screen *vscreen;
276 struct vl_context *vctx;
277 XvMCContextPrivate *context_priv;
278
279 XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying context %p.\n", context);
280
281 assert(dpy);
282
283 if (!context || !context->privData)
284 return XvMCBadContext;
285
286 context_priv = context->privData;
287 vctx = context_priv->vctx;
288 pipe_surface_reference(&context_priv->backbuffer, NULL);
289 vscreen = vctx->vscreen;
290 vl_video_destroy(vctx);
291 vl_screen_destroy(vscreen);
292 FREE(context_priv);
293 context->privData = NULL;
294
295 XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p destroyed.\n", context);
296
297 return Success;
298 }