g3dvl: Implement XvMC using pipe_video_context.
[mesa.git] / src / 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 "xvmc_private.h"
11
12 static Status Validate(Display *dpy, XvPortID port, int surface_type_id,
13 unsigned int width, unsigned int height, int flags,
14 bool *found_port, int *screen, int *chroma_format, int *mc_type)
15 {
16 bool found_surface = false;
17 XvAdaptorInfo *adaptor_info;
18 unsigned int num_adaptors;
19 int num_types;
20 unsigned int max_width, max_height;
21 Status ret;
22
23 assert(dpy);
24 assert(found_port);
25 assert(screen);
26 assert(chroma_format);
27 assert(mc_type);
28
29 *found_port = false;
30
31 for (unsigned int i = 0; i < XScreenCount(dpy); ++i)
32 {
33 ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info);
34 if (ret != Success)
35 return ret;
36
37 for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j)
38 {
39 for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k)
40 {
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 {
51 XvFreeAdaptorInfo(adaptor_info);
52 return BadAlloc;
53 }
54
55 for (unsigned int l = 0; l < num_types && !found_surface; ++l)
56 {
57 if (surface_info[l].surface_type_id != surface_type_id)
58 continue;
59
60 found_surface = true;
61 max_width = surface_info[l].max_width;
62 max_height = surface_info[l].max_height;
63 *chroma_format = surface_info[l].chroma_format;
64 *mc_type = surface_info[l].mc_type;
65 *screen = i;
66 }
67
68 XFree(surface_info);
69 }
70 }
71
72 XvFreeAdaptorInfo(adaptor_info);
73 }
74
75 if (!*found_port)
76 return XvBadPort;
77 if (!found_surface)
78 return BadMatch;
79 if (width > max_width || height > max_height)
80 return BadValue;
81 if (flags != XVMC_DIRECT && flags != 0)
82 return BadValue;
83
84 return Success;
85 }
86
87 static enum pipe_video_profile ProfileToPipe(int xvmc_profile)
88 {
89 if (xvmc_profile & XVMC_MPEG_1)
90 assert(0);
91 if (xvmc_profile & XVMC_MPEG_2)
92 return PIPE_VIDEO_PROFILE_MPEG2_MAIN;
93 if (xvmc_profile & XVMC_H263)
94 assert(0);
95 if (xvmc_profile & XVMC_MPEG_4)
96 assert(0);
97
98 assert(0);
99
100 return -1;
101 }
102
103 static enum pipe_video_chroma_format FormatToPipe(int xvmc_format)
104 {
105 switch (xvmc_format)
106 {
107 case XVMC_CHROMA_FORMAT_420:
108 return PIPE_VIDEO_CHROMA_FORMAT_420;
109 case XVMC_CHROMA_FORMAT_422:
110 return PIPE_VIDEO_CHROMA_FORMAT_422;
111 case XVMC_CHROMA_FORMAT_444:
112 return PIPE_VIDEO_CHROMA_FORMAT_444;
113 default:
114 assert(0);
115 }
116
117 return -1;
118 }
119
120 Status XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id,
121 int width, int height, int flags, XvMCContext *context)
122 {
123 bool found_port;
124 int scrn;
125 int chroma_format;
126 int mc_type;
127 Status ret;
128 struct pipe_screen *screen;
129 struct pipe_video_context *vpipe;
130 XvMCContextPrivate *context_priv;
131
132 assert(dpy);
133
134 if (!context)
135 return XvMCBadContext;
136
137 ret = Validate(dpy, port, surface_type_id, width, height, flags,
138 &found_port, &scrn, &chroma_format, &mc_type);
139
140 /* Success and XvBadPort have the same value */
141 if (ret != Success || !found_port)
142 return ret;
143
144 context_priv = CALLOC(1, sizeof(XvMCContextPrivate));
145 if (!context_priv)
146 return BadAlloc;
147
148 /* TODO: Reuse screen if process creates another context */
149 screen = vl_screen_create(dpy, scrn);
150
151 if (!screen)
152 {
153 FREE(context_priv);
154 return BadAlloc;
155 }
156
157 vpipe = vl_video_create(screen, ProfileToPipe(mc_type),
158 FormatToPipe(chroma_format), width, height);
159
160 if (!vpipe)
161 {
162 screen->destroy(screen);
163 FREE(context_priv);
164 return BadAlloc;
165 }
166
167 context_priv->vpipe = vpipe;
168
169 context->context_id = XAllocID(dpy);
170 context->surface_type_id = surface_type_id;
171 context->width = width;
172 context->height = height;
173 context->flags = flags;
174 context->port = port;
175 context->privData = context_priv;
176
177 SyncHandle();
178
179 return Success;
180 }
181
182 Status XvMCDestroyContext(Display *dpy, XvMCContext *context)
183 {
184 struct pipe_screen *screen;
185 struct pipe_video_context *vpipe;
186 XvMCContextPrivate *context_priv;
187
188 assert(dpy);
189
190 if (!context || !context->privData)
191 return XvMCBadContext;
192
193 context_priv = context->privData;
194 vpipe = context_priv->vpipe;
195 pipe_surface_reference(&context_priv->backbuffer, NULL);
196 screen = vpipe->screen;
197 vpipe->destroy(vpipe);
198 screen->destroy(screen);
199 FREE(context_priv);
200 context->privData = NULL;
201
202 return Success;
203 }