Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / kdrive / ephyr / ephyrhostglx.c
CommitLineData
a09e091a
JB
1/*
2 * Xephyr - A kdrive X server thats runs in a host X window.
3 * Authored by Matthew Allum <mallum@openedhand.com>
4 *
5 * Copyright © 2007 OpenedHand Ltd
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of OpenedHand Ltd not be used in
12 * advertising or publicity pertaining to distribution of the software without
13 * specific, written prior permission. OpenedHand Ltd makes no
14 * representations about the suitability of this software for any purpose. It
15 * is provided "as is" without express or implied warranty.
16 *
17 * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
24 *
25 * a lots of the content of this file has been adapted from the mesa source
26 * code.
27 * Authors:
28 * Dodji Seketeli <dodji@openedhand.com>
29 */
30#ifdef HAVE_CONFIG_H
31#include <kdrive-config.h>
32#endif
33
34#include <X11/Xdefs.h>
35#include <X11/Xmd.h>
36#include <GL/glxproto.h>
37#include <xcb/glx.h>
38#include "ephyrhostglx.h"
39#define _HAVE_XALLOC_DECLS
40#include "ephyrlog.h"
41#include "hostx.h"
42
43static int glx_major, glx_minor;
44
45enum VisualConfRequestType {
46 EPHYR_GET_FB_CONFIG,
47 EPHYR_VENDOR_PRIV_GET_FB_CONFIG_SGIX,
48 EPHYR_GET_VISUAL_CONFIGS
49};
50
51static Bool ephyrHostGLXGetVisualConfigsInternal
52 (enum VisualConfRequestType a_type,
53 xcb_glx_get_visual_configs_reply_t *reply,
54 int32_t a_screen,
55 int32_t *a_num_visuals,
56 int32_t *a_num_props,
57 int32_t *a_props_buf_size,
58 int32_t **a_props_buf);
59
60Bool
61ephyrHostGLXQueryVersion(int *a_major, int *a_minor)
62{
63 Bool is_ok = FALSE;
64 xcb_connection_t *conn = hostx_get_xcbconn();
65 xcb_glx_query_version_cookie_t cookie;
66 xcb_glx_query_version_reply_t *reply;
67
68 EPHYR_RETURN_VAL_IF_FAIL(a_major && a_minor, FALSE);
69 EPHYR_LOG("enter\n");
70
71 if (glx_major) {
72 *a_major = glx_major;
73 *a_minor = glx_minor;
74 return TRUE;
75 }
76
77 /* Send the glXQueryVersion request */
78 cookie = xcb_glx_query_version(conn, 2, 1);
79 reply = xcb_glx_query_version_reply(conn, cookie, NULL);
80 if (!reply)
81 goto out;
82 *a_major = reply->major_version;
83 *a_minor = reply->minor_version;
84 free(reply);
85
86 EPHYR_LOG("major:%d, minor:%d\n", *a_major, *a_minor);
87
88 is_ok = TRUE;
89 out:
90 EPHYR_LOG("leave\n");
91 return is_ok;
92}
93
94Bool
95ephyrHostGLXGetString(int a_context_tag,
96 int a_string_name,
97 char **a_string)
98{
99 Bool is_ok = FALSE;
100 xcb_connection_t *conn = hostx_get_xcbconn();
101 xcb_glx_get_string_cookie_t cookie;
102 xcb_glx_get_string_reply_t *reply;
103
104 EPHYR_RETURN_VAL_IF_FAIL(conn && a_string, FALSE);
105
106 EPHYR_LOG("enter\n");
107 cookie = xcb_glx_get_string(conn, a_context_tag, a_string_name);
108 reply = xcb_glx_get_string_reply(conn, cookie, NULL);
109 if (!reply)
110 goto out;
111 *a_string = malloc(reply->n + 1);
112 memcpy(*a_string, xcb_glx_get_string_string(reply), reply->n);
113 (*a_string)[reply->n] = '\0';
114 free(reply);
115 is_ok = TRUE;
116out:
117 EPHYR_LOG("leave\n");
118 return is_ok;
119}
120
121Bool ephyrHostGLXQueryServerString(int a_screen_number,
122 int a_string_name,
123 char **a_string)
124{
125 Bool is_ok = FALSE;
126 xcb_connection_t *conn = hostx_get_xcbconn();
127 int default_screen = hostx_get_screen();
128 xcb_glx_query_server_string_cookie_t cookie;
129 xcb_glx_query_server_string_reply_t *reply;
130
131 EPHYR_RETURN_VAL_IF_FAIL(conn && a_string, FALSE);
132
133 EPHYR_LOG("enter\n");
134 cookie = xcb_glx_query_server_string(conn, default_screen, a_string_name);
135 reply = xcb_glx_query_server_string_reply(conn, cookie, NULL);
136 if (!reply)
137 goto out;
138 *a_string = malloc(reply->str_len + 1);
139 memcpy(*a_string, xcb_glx_query_server_string_string(reply), reply->str_len);
140 (*a_string)[reply->str_len] = '\0';
141 free(reply);
142 is_ok = TRUE;
143out:
144 EPHYR_LOG("leave\n");
145 return is_ok;
146}
147
148static Bool
149ephyrHostGLXGetVisualConfigsInternal(enum VisualConfRequestType a_type,
150 xcb_glx_get_visual_configs_reply_t *reply,
151 int32_t a_screen,
152 int32_t * a_num_visuals,
153 int32_t * a_num_props,
154 int32_t * a_props_buf_size,
155 int32_t ** a_props_buf)
156{
157 Bool is_ok = FALSE;
158 int num_props = 0, num_visuals = 0, props_buf_size = 0;
159 int props_per_visual_size = 0;
160 int32_t *props_buf = NULL;
161
162 if (!reply->num_visuals) {
163 EPHYR_LOG_ERROR("screen does not support GL rendering\n");
164 goto out;
165 }
166 num_visuals = reply->num_visuals;
167
168 num_props = reply->num_properties;
169
170 if (a_type != EPHYR_GET_VISUAL_CONFIGS) {
171 num_props *= 2;
172 }
173 props_per_visual_size = num_props * sizeof(uint32_t);
174 props_buf_size = props_per_visual_size * reply->num_visuals;
175 props_buf = malloc(props_buf_size);
176 if (!props_buf)
177 goto out;
178 memcpy(props_buf, xcb_glx_get_visual_configs_property_list(reply),
179 props_buf_size);
180
181 *a_num_visuals = num_visuals;
182 *a_num_props = reply->num_properties;
183 *a_props_buf_size = props_buf_size;
184 *a_props_buf = props_buf;
185 is_ok = TRUE;
186
187out:
188 return is_ok;
189}
190
191Bool
192ephyrHostGLXGetVisualConfigs(int32_t a_screen,
193 int32_t * a_num_visuals,
194 int32_t * a_num_props,
195 int32_t * a_props_buf_size, int32_t ** a_props_buf)
196{
197 Bool is_ok = FALSE;
198 xcb_glx_get_visual_configs_cookie_t cookie;
199 xcb_glx_get_visual_configs_reply_t *reply;
200 xcb_connection_t *conn = hostx_get_xcbconn();
201 int screen = hostx_get_screen();
202
203 EPHYR_LOG("enter\n");
204 cookie = xcb_glx_get_visual_configs(conn, screen);
205 reply = xcb_glx_get_visual_configs_reply(conn, cookie, NULL);
206 if (!reply)
207 goto out;
208 is_ok = ephyrHostGLXGetVisualConfigsInternal
209 (EPHYR_GET_VISUAL_CONFIGS,
210 reply,
211 a_screen,
212 a_num_visuals,
213 a_num_props,
214 a_props_buf_size,
215 a_props_buf);
216
217out:
218 free(reply);
219 EPHYR_LOG("leave:%d\n", is_ok);
220 return is_ok;
221}
222
223Bool
224ephyrHostGLXVendorPrivGetFBConfigsSGIX(int a_screen,
225 int32_t * a_num_visuals,
226 int32_t * a_num_props,
227 int32_t * a_props_buf_size,
228 int32_t ** a_props_buf)
229{
230 Bool is_ok=FALSE;
231 xcb_connection_t *conn = hostx_get_xcbconn();
232 int screen = hostx_get_screen();
233 xcb_glx_vendor_private_with_reply_cookie_t cookie;
234 union {
235 xcb_glx_vendor_private_with_reply_reply_t *vprep;
236 xcb_glx_get_visual_configs_reply_t *rep;
237 } reply;
238
239 EPHYR_LOG("enter\n");
240 cookie = xcb_glx_vendor_private_with_reply(conn,
241 X_GLXvop_GetFBConfigsSGIX,
242 0, 4, (uint8_t *)&screen);
243 reply.vprep = xcb_glx_vendor_private_with_reply_reply(conn, cookie, NULL);
244 if (!reply.vprep)
245 goto out;
246 is_ok = ephyrHostGLXGetVisualConfigsInternal
247 (EPHYR_VENDOR_PRIV_GET_FB_CONFIG_SGIX,
248 reply.rep,
249 a_screen,
250 a_num_visuals,
251 a_num_props,
252 a_props_buf_size,
253 a_props_buf);
254out:
255 free(reply.vprep);
256 EPHYR_LOG("leave\n");
257 return is_ok;
258}
259
260Bool
261ephyrHostGLXSendClientInfo(int32_t a_major, int32_t a_minor,
262 const char *a_extension_list)
263{
264 xcb_connection_t *conn = hostx_get_xcbconn();
265 int size;
266
267 EPHYR_RETURN_VAL_IF_FAIL(conn && a_extension_list, FALSE);
268
269 size = strlen (a_extension_list) + 1;
270 xcb_glx_client_info(conn, a_major, a_minor, size, a_extension_list);
271
272 return TRUE;
273}
274
275Bool
276ephyrHostGLXCreateContext(int a_screen,
277 int a_generic_id,
278 int a_context_id,
279 int a_share_list_ctxt_id,
280 int a_render_type,
281 Bool a_direct,
282 int code)
283{
284 xcb_connection_t *conn = hostx_get_xcbconn();
285 Bool is_ok = FALSE;
286 int remote_context_id = 0;
287
288 EPHYR_LOG("enter. screen:%d, generic_id:%d, contextid:%d, rendertype:%d, "
289 "direct:%d\n", a_screen, a_generic_id, a_context_id,
290 a_render_type, a_direct);
291
292 if (!hostx_allocate_resource_id_peer(a_context_id, &remote_context_id)) {
293 EPHYR_LOG_ERROR("failed to peer the context id %d host X",
294 remote_context_id);
295 goto out;
296 }
297
298 switch (code) {
299 case X_GLXCreateContext: {
300 xcb_glx_create_context(conn,
301 remote_context_id,
302 a_generic_id,
303 hostx_get_screen(),
304 a_share_list_ctxt_id,
305 a_direct);
306 }
307
308 case X_GLXCreateNewContext: {
309 xcb_glx_create_new_context(conn,
310 remote_context_id,
311 a_generic_id,
312 hostx_get_screen(),
313 a_render_type,
314 a_share_list_ctxt_id,
315 a_direct);
316 }
317
318 default:
319 /* This should never be reached !*/
320 EPHYR_LOG("Internal error! Invalid CreateContext code!\n");
321 }
322
323 is_ok = TRUE;
324
325 out:
326 EPHYR_LOG("leave\n");
327 return is_ok;
328}
329
330Bool
331ephyrHostDestroyContext(int a_ctxt_id)
332{
333 xcb_connection_t *conn = hostx_get_xcbconn();
334 Bool is_ok = FALSE;
335 int remote_ctxt_id = 0;
336
337 EPHYR_LOG("enter:%d\n", a_ctxt_id);
338
339 if (!hostx_get_resource_id_peer(a_ctxt_id, &remote_ctxt_id)) {
340 EPHYR_LOG_ERROR("failed to get remote glx ctxt id\n");
341 goto out;
342 }
343 EPHYR_LOG("host context id:%d\n", remote_ctxt_id);
344
345 xcb_glx_destroy_context(conn, remote_ctxt_id);
346
347 is_ok = TRUE;
348
349 out:
350 EPHYR_LOG("leave\n");
351 return is_ok;
352}
353
354Bool
355ephyrHostGLXMakeCurrent(int a_drawable, int a_readable,
356 int a_glx_ctxt_id, int a_old_ctxt_tag, int *a_ctxt_tag)
357{
358 xcb_connection_t *conn = hostx_get_xcbconn();
359 Bool is_ok = FALSE;
360 int remote_glx_ctxt_id = 0;
361
362 EPHYR_RETURN_VAL_IF_FAIL(a_ctxt_tag, FALSE);
363
364 EPHYR_LOG("enter. drawable:%d, read:%d, context:%d, oldtag:%d\n",
365 a_drawable, a_readable, a_glx_ctxt_id, a_old_ctxt_tag);
366
367 if (!hostx_get_resource_id_peer(a_glx_ctxt_id, &remote_glx_ctxt_id)) {
368 EPHYR_LOG_ERROR("failed to get remote glx ctxt id\n");
369 goto out;
370 }
371
372 /* If both drawables are the same, use the old MakeCurrent request.
373 * Otherwise, if we have GLX 1.3 or higher, use the MakeContextCurrent
374 * request which supports separate read and draw targets. Failing that,
375 * try the SGI MakeCurrentRead extension. Logic cribbed from Mesa. */
376 if (a_drawable == a_readable) {
377 xcb_glx_make_current_cookie_t cookie;
378 xcb_glx_make_current_reply_t *reply;
379 cookie = xcb_glx_make_current(conn,
380 a_drawable,
381 remote_glx_ctxt_id,
382 a_old_ctxt_tag);
383 reply = xcb_glx_make_current_reply(conn, cookie, NULL);
384 if (!reply)
385 goto out;
386 *a_ctxt_tag = reply->context_tag;
387 free(reply);
388 }
389 else if (glx_major > 1 || glx_minor >= 3) {
390 xcb_glx_make_context_current_cookie_t cookie;
391 xcb_glx_make_context_current_reply_t *reply;
392 cookie = xcb_glx_make_context_current(conn,
393 a_old_ctxt_tag,
394 a_drawable,
395 a_readable,
396 remote_glx_ctxt_id);
397 reply = xcb_glx_make_context_current_reply(conn, cookie, NULL);
398 if (!reply)
399 goto out;
400 *a_ctxt_tag = reply->context_tag;
401 free(reply);
402 }
403 else {
404 xcb_glx_vendor_private_with_reply_cookie_t cookie;
405 xcb_glx_vendor_private_with_reply_reply_t *reply;
406 uint32_t data[3] = {
407 a_drawable, a_readable, remote_glx_ctxt_id,
408 };
409
410 EPHYR_LOG("enter\n");
411 cookie = xcb_glx_vendor_private_with_reply(conn,
412 X_GLXvop_MakeCurrentReadSGI,
413 a_old_ctxt_tag,
414 sizeof(data),
415 (uint8_t *)data);
416 reply = xcb_glx_vendor_private_with_reply_reply(conn, cookie, NULL);
417
418 *a_ctxt_tag = reply->retval;
419
420 free(reply);
421 }
422
423 EPHYR_LOG("context tag:%d\n", *a_ctxt_tag);
424 is_ok = TRUE;
425
426 out:
427 EPHYR_LOG("leave\n");
428 return is_ok;
429}
430
431Bool
432ephyrHostGetIntegerValue(int a_current_context_tag, int a_int, int *a_val)
433{
434 xcb_connection_t *conn = hostx_get_xcbconn();
435 Bool is_ok = FALSE;
436 int size = 0;
437 xcb_glx_get_integerv_cookie_t cookie;
438 xcb_glx_get_integerv_reply_t *reply;
439
440 EPHYR_RETURN_VAL_IF_FAIL(a_val, FALSE);
441
442 EPHYR_LOG("enter\n");
443 cookie = xcb_glx_get_integerv(conn, a_current_context_tag, a_int);
444 reply = xcb_glx_get_integerv_reply(conn, cookie, NULL);
445 if (!reply)
446 goto out;
447 size = reply->n;
448 if (!size) {
449 EPHYR_LOG_ERROR("X_GLsop_GetIngerv failed\n");
450 goto out;
451 }
452 *a_val = reply->datum;
453 is_ok = TRUE;
454
455out:
456 free(reply);
457 EPHYR_LOG("leave\n");
458 return is_ok;
459}
460
461Bool
462ephyrHostIsContextDirect(int a_ctxt_id, int *a_is_direct)
463{
464 Bool is_ok = FALSE;
465 xcb_connection_t *conn = hostx_get_xcbconn();
466 xcb_glx_is_direct_cookie_t cookie;
467 xcb_glx_is_direct_reply_t *reply = NULL;
468 int remote_glx_ctxt_id = 0;
469
470 EPHYR_LOG("enter\n");
471 if (!hostx_get_resource_id_peer (a_ctxt_id, &remote_glx_ctxt_id)) {
472 EPHYR_LOG_ERROR ("failed to get remote glx ctxt id\n");
473 goto out;
474 }
475
476 /* Send the glXIsDirect request */
477 cookie = xcb_glx_is_direct(conn, remote_glx_ctxt_id);
478 reply = xcb_glx_is_direct_reply(conn, cookie, NULL);
479 if (!reply) {
480 EPHYR_LOG_ERROR("fail in reading reply from host\n");
481 goto out;
482 }
483 *a_is_direct = reply->is_direct;
484 is_ok = TRUE;
485
486out:
487 free(reply);
488 EPHYR_LOG("leave\n");
489 return is_ok;
490}