Merge branch 'master' of ssh://git.freedesktop.org/git/mesa/mesa into pipe-video
[mesa.git] / src / gallium / winsys / g3dvl / dri / dri_winsys.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 <vl_winsys.h>
29 #include <driclient.h>
30 #include <pipe/p_video_context.h>
31 #include <pipe/p_state.h>
32 #include <util/u_memory.h>
33 #include <util/u_hash.h>
34 #include <util/u_hash_table.h>
35 #include <state_tracker/drm_api.h>
36 #include <X11/Xlibint.h>
37
38 struct vl_dri_screen
39 {
40 struct vl_screen base;
41 struct drm_api *api;
42 dri_screen_t *dri_screen;
43 struct util_hash_table *drawable_table;
44 Drawable last_seen_drawable;
45 };
46
47 struct vl_dri_context
48 {
49 struct vl_context base;
50 int fd;
51 };
52
53 static struct pipe_surface*
54 vl_dri2_get_front(struct vl_dri_screen *vl_dri_scrn, Drawable drawable)
55 {
56 int w, h;
57 unsigned int attachments[1] = {DRI_BUFFER_FRONT_LEFT};
58 int count;
59 DRI2Buffer *dri2_front;
60 struct pipe_resource *front_tex;
61 struct pipe_surface *front_surf = NULL;
62
63 assert(vl_dri_scrn);
64
65 dri2_front = DRI2GetBuffers(vl_dri_scrn->dri_screen->display,
66 drawable, &w, &h, attachments, 1, &count);
67
68 assert(count == 1);
69
70 if (dri2_front) {
71 struct winsys_handle dri2_front_handle =
72 {
73 .type = DRM_API_HANDLE_TYPE_SHARED,
74 .handle = dri2_front->name,
75 .stride = dri2_front->pitch
76 };
77 struct pipe_resource template;
78
79 memset(&template, 0, sizeof(struct pipe_resource));
80 template.target = PIPE_TEXTURE_2D;
81 template.format = PIPE_FORMAT_B8G8R8X8_UNORM;
82 template.last_level = 0;
83 template.width0 = w;
84 template.height0 = h;
85 template.depth0 = 1;
86 template.usage = PIPE_USAGE_STATIC;
87 template.bind = PIPE_BIND_RENDER_TARGET;
88 template.flags = 0;
89
90 front_tex = vl_dri_scrn->base.pscreen->resource_from_handle(vl_dri_scrn->base.pscreen, &template, &dri2_front_handle);
91 if (front_tex)
92 front_surf = vl_dri_scrn->base.pscreen->get_tex_surface(vl_dri_scrn->base.pscreen,
93 front_tex, 0, 0, 0,
94 PIPE_BIND_RENDER_TARGET);
95 pipe_resource_reference(&front_tex, NULL);
96 Xfree(dri2_front);
97 }
98
99 return front_surf;
100 }
101
102 static void
103 vl_dri2_flush_frontbuffer(struct pipe_screen *screen,
104 struct pipe_surface *surf, void *context_private)
105 {
106 struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)context_private;
107 struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
108
109 assert(screen);
110 assert(surf);
111 assert(context_private);
112
113 dri2CopyDrawable(vl_dri_scrn->dri_screen, vl_dri_scrn->last_seen_drawable,
114 DRI_BUFFER_FRONT_LEFT, DRI_BUFFER_FAKE_FRONT_LEFT);
115 }
116
117 struct pipe_surface*
118 vl_drawable_surface_get(struct vl_screen *vscreen, Drawable drawable)
119 {
120 struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen;
121
122 assert(vscreen);
123
124 if (vl_dri_scrn->last_seen_drawable != drawable) {
125 /* Hash table business depends on this equality */
126 assert(None == NULL);
127 Drawable lookup_drawable = (Drawable)util_hash_table_get(vl_dri_scrn->drawable_table, (void*)drawable);
128 if (lookup_drawable == None) {
129 dri2CreateDrawable(vl_dri_scrn->dri_screen, drawable);
130 util_hash_table_set(vl_dri_scrn->drawable_table, (void*)drawable, (void*)drawable);
131 }
132 vl_dri_scrn->last_seen_drawable = drawable;
133 }
134
135 return vl_dri2_get_front(vl_dri_scrn, drawable);
136 }
137
138 void*
139 vl_contextprivate_get(struct vl_context *vctx, struct pipe_surface *displaytarget)
140 {
141 return vctx;
142 }
143
144 static unsigned drawable_hash(void *key)
145 {
146 Drawable drawable = (Drawable)key;
147 assert(drawable != None);
148 return util_hash_crc32(&drawable, sizeof(Drawable));
149 }
150
151 static int drawable_cmp(void *key1, void *key2)
152 {
153 Drawable d1 = (Drawable)key1;
154 Drawable d2 = (Drawable)key2;
155 assert(d1 != None);
156 assert(d2 != None);
157 return d1 != d2;
158 }
159
160 static enum pipe_error
161 drawable_destroy(void *key, void *value, void *data)
162 {
163 Drawable drawable = (Drawable)key;
164 struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)data;
165
166 assert(drawable != None);
167 assert(value);
168 assert(data);
169
170 dri2DestroyDrawable(vl_dri_scrn->dri_screen, drawable);
171
172 return PIPE_OK;
173 }
174
175 struct vl_screen*
176 vl_screen_create(Display *display, int screen)
177 {
178 struct vl_dri_screen *vl_dri_scrn;
179 struct drm_create_screen_arg arg;
180
181 assert(display);
182
183 vl_dri_scrn = CALLOC_STRUCT(vl_dri_screen);
184 if (!vl_dri_scrn)
185 goto no_struct;
186
187 if (dri2CreateScreen(display, screen, &vl_dri_scrn->dri_screen))
188 goto no_dri2screen;
189
190 vl_dri_scrn->api = drm_api_create();
191 if (!vl_dri_scrn->api)
192 goto no_drmapi;
193
194 arg.mode = DRM_CREATE_NORMAL;
195
196 vl_dri_scrn->base.pscreen = vl_dri_scrn->api->create_screen(vl_dri_scrn->api,
197 vl_dri_scrn->dri_screen->fd,
198 &arg);
199
200 if (!vl_dri_scrn->base.pscreen)
201 goto no_pscreen;
202
203 vl_dri_scrn->drawable_table = util_hash_table_create(&drawable_hash, &drawable_cmp);
204 if (!vl_dri_scrn->drawable_table)
205 goto no_hash;
206
207 vl_dri_scrn->last_seen_drawable = None;
208 vl_dri_scrn->base.pscreen->flush_frontbuffer = vl_dri2_flush_frontbuffer;
209
210 return &vl_dri_scrn->base;
211
212 no_hash:
213 vl_dri_scrn->base.pscreen->destroy(vl_dri_scrn->base.pscreen);
214 no_pscreen:
215 vl_dri_scrn->api->destroy(vl_dri_scrn->api);
216 no_drmapi:
217 dri2DestroyScreen(vl_dri_scrn->dri_screen);
218 no_dri2screen:
219 FREE(vl_dri_scrn);
220 no_struct:
221 return NULL;
222 }
223
224 void vl_screen_destroy(struct vl_screen *vscreen)
225 {
226 struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen;
227
228 assert(vscreen);
229
230 util_hash_table_foreach(vl_dri_scrn->drawable_table, drawable_destroy, vl_dri_scrn);
231 util_hash_table_destroy(vl_dri_scrn->drawable_table);
232 vl_dri_scrn->base.pscreen->destroy(vl_dri_scrn->base.pscreen);
233 if (vl_dri_scrn->api->destroy)
234 vl_dri_scrn->api->destroy(vl_dri_scrn->api);
235 dri2DestroyScreen(vl_dri_scrn->dri_screen);
236 FREE(vl_dri_scrn);
237 }
238
239 struct vl_context*
240 vl_video_create(struct vl_screen *vscreen,
241 enum pipe_video_profile profile,
242 enum pipe_video_chroma_format chroma_format,
243 unsigned width, unsigned height)
244 {
245 struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen;
246 struct vl_dri_context *vl_dri_ctx;
247
248 vl_dri_ctx = CALLOC_STRUCT(vl_dri_context);
249 if (!vl_dri_ctx)
250 goto no_struct;
251
252 if (!vscreen->pscreen->video_context_create) {
253 debug_printf("[G3DVL] No video support found on %s/%s.\n",
254 vscreen->pscreen->get_vendor(vscreen->pscreen),
255 vscreen->pscreen->get_name(vscreen->pscreen));
256 goto no_vpipe;
257 }
258
259 vl_dri_ctx->base.vpipe = vscreen->pscreen->video_context_create(vscreen->pscreen,
260 profile, chroma_format,
261 width, height,
262 vl_dri_ctx);
263
264 if (!vl_dri_ctx->base.vpipe)
265 goto no_vpipe;
266
267 vl_dri_ctx->base.vpipe->priv = vl_dri_ctx;
268 vl_dri_ctx->base.vscreen = vscreen;
269 vl_dri_ctx->fd = vl_dri_scrn->dri_screen->fd;
270
271 return &vl_dri_ctx->base;
272
273 no_vpipe:
274 FREE(vl_dri_ctx);
275 no_struct:
276 return NULL;
277 }
278
279 void vl_video_destroy(struct vl_context *vctx)
280 {
281 struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)vctx;
282
283 assert(vctx);
284
285 vl_dri_ctx->base.vpipe->destroy(vl_dri_ctx->base.vpipe);
286 FREE(vl_dri_ctx);
287 }