Merge branch 'mesa_7_6_branch'
[mesa.git] / src / gallium / state_trackers / xorg / xvmc / context.c
1 #include <assert.h>
2 #include <X11/Xlibint.h>
3 #include <X11/extensions/XvMClib.h>
4 #include <pipe/p_screen.h>
5 #include <pipe/p_video_context.h>
6 #include <pipe/p_video_state.h>
7 #include <pipe/p_state.h>
8 #include <vl_winsys.h>
9 #include <util/u_memory.h>
10 #include <util/u_debug.h>
11 #include "xvmc_private.h"
12
13 static Status Validate(Display *dpy, XvPortID port, int surface_type_id,
14 unsigned int width, unsigned int height, int flags,
15 bool *found_port, int *screen, int *chroma_format,
16 int *mc_type, int *surface_flags)
17 {
18 bool found_surface = false;
19 XvAdaptorInfo *adaptor_info;
20 unsigned int num_adaptors;
21 int num_types;
22 unsigned int max_width, max_height;
23 Status ret;
24
25 assert(dpy);
26 assert(found_port);
27 assert(screen);
28 assert(chroma_format);
29 assert(mc_type);
30 assert(surface_flags);
31
32 *found_port = false;
33
34 for (unsigned int i = 0; i < XScreenCount(dpy); ++i) {
35 ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info);
36 if (ret != Success)
37 return ret;
38
39 for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j) {
40 for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k) {
41 XvMCSurfaceInfo *surface_info;
42
43 if (adaptor_info[j].base_id + k != port)
44 continue;
45
46 *found_port = true;
47
48 surface_info = XvMCListSurfaceTypes(dpy, adaptor_info[j].base_id, &num_types);
49 if (!surface_info) {
50 XvFreeAdaptorInfo(adaptor_info);
51 return BadAlloc;
52 }
53
54 for (unsigned int l = 0; l < num_types && !found_surface; ++l) {
55 if (surface_info[l].surface_type_id != surface_type_id)
56 continue;
57
58 found_surface = true;
59 max_width = surface_info[l].max_width;
60 max_height = surface_info[l].max_height;
61 *chroma_format = surface_info[l].chroma_format;
62 *mc_type = surface_info[l].mc_type;
63 *surface_flags = surface_info[l].flags;
64 *screen = i;
65 }
66
67 XFree(surface_info);
68 }
69 }
70
71 XvFreeAdaptorInfo(adaptor_info);
72 }
73
74 if (!*found_port)
75 return XvBadPort;
76 if (!found_surface)
77 return BadMatch;
78 if (width > max_width || height > max_height)
79 return BadValue;
80 if (flags != XVMC_DIRECT && flags != 0)
81 return BadValue;
82
83 return Success;
84 }
85
86 static enum pipe_video_profile ProfileToPipe(int xvmc_profile)
87 {
88 if (xvmc_profile & XVMC_MPEG_1)
89 assert(0);
90 if (xvmc_profile & XVMC_MPEG_2)
91 return PIPE_VIDEO_PROFILE_MPEG2_MAIN;
92 if (xvmc_profile & XVMC_H263)
93 assert(0);
94 if (xvmc_profile & XVMC_MPEG_4)
95 assert(0);
96
97 assert(0);
98
99 return -1;
100 }
101
102 static enum pipe_video_chroma_format FormatToPipe(int xvmc_format)
103 {
104 switch (xvmc_format) {
105 case XVMC_CHROMA_FORMAT_420:
106 return PIPE_VIDEO_CHROMA_FORMAT_420;
107 case XVMC_CHROMA_FORMAT_422:
108 return PIPE_VIDEO_CHROMA_FORMAT_422;
109 case XVMC_CHROMA_FORMAT_444:
110 return PIPE_VIDEO_CHROMA_FORMAT_444;
111 default:
112 assert(0);
113 }
114
115 return -1;
116 }
117
118 Status XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id,
119 int width, int height, int flags, XvMCContext *context)
120 {
121 bool found_port;
122 int scrn;
123 int chroma_format;
124 int mc_type;
125 int surface_flags;
126 Status ret;
127 struct pipe_screen *screen;
128 struct pipe_video_context *vpipe;
129 XvMCContextPrivate *context_priv;
130
131 assert(dpy);
132
133 if (!context)
134 return XvMCBadContext;
135
136 ret = Validate(dpy, port, surface_type_id, width, height, flags,
137 &found_port, &scrn, &chroma_format, &mc_type, &surface_flags);
138
139 /* Success and XvBadPort have the same value */
140 if (ret != Success || !found_port)
141 return ret;
142
143 /* XXX: Current limits */
144 if (chroma_format != XVMC_CHROMA_FORMAT_420) {
145 debug_printf("[XvMCg3dvl] Cannot decode requested surface type. Unsupported chroma format.\n");
146 return BadImplementation;
147 }
148 if (mc_type != (XVMC_MOCOMP | XVMC_MPEG_2)) {
149 debug_printf("[XvMCg3dvl] Cannot decode requested surface type. Non-MPEG2/Mocomp acceleration unsupported.\n");
150 return BadImplementation;
151 }
152 if (!(surface_flags & XVMC_INTRA_UNSIGNED)) {
153 debug_printf("[XvMCg3dvl] Cannot decode requested surface type. Signed intra unsupported.\n");
154 return BadImplementation;
155 }
156
157 context_priv = CALLOC(1, sizeof(XvMCContextPrivate));
158 if (!context_priv)
159 return BadAlloc;
160
161 /* TODO: Reuse screen if process creates another context */
162 screen = vl_screen_create(dpy, scrn);
163
164 if (!screen) {
165 FREE(context_priv);
166 return BadAlloc;
167 }
168
169 vpipe = vl_video_create(screen, ProfileToPipe(mc_type),
170 FormatToPipe(chroma_format), width, height);
171
172 if (!vpipe) {
173 screen->destroy(screen);
174 FREE(context_priv);
175 return BadAlloc;
176 }
177
178 context_priv->vpipe = vpipe;
179
180 context->context_id = XAllocID(dpy);
181 context->surface_type_id = surface_type_id;
182 context->width = width;
183 context->height = height;
184 context->flags = flags;
185 context->port = port;
186 context->privData = context_priv;
187
188 SyncHandle();
189
190 return Success;
191 }
192
193 Status XvMCDestroyContext(Display *dpy, XvMCContext *context)
194 {
195 struct pipe_screen *screen;
196 struct pipe_video_context *vpipe;
197 XvMCContextPrivate *context_priv;
198
199 assert(dpy);
200
201 if (!context || !context->privData)
202 return XvMCBadContext;
203
204 context_priv = context->privData;
205 vpipe = context_priv->vpipe;
206 pipe_surface_reference(&context_priv->backbuffer, NULL);
207 screen = vpipe->screen;
208 vpipe->destroy(vpipe);
209 screen->destroy(screen);
210 FREE(context_priv);
211 context->privData = NULL;
212
213 return Success;
214 }