glx: Avoid atof() when computing the server's GLX version
[mesa.git] / src / glx / indirect_glx.c
1 /*
2 * Copyright © 2010 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Soft-
6 * ware"), to deal in the Software without restriction, including without
7 * limitation the rights to use, copy, modify, merge, publish, distribute,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, provided that the above copyright
10 * notice(s) and this permission notice appear in all copies of the Soft-
11 * ware and that both the above copyright notice(s) and this permission
12 * notice appear in supporting documentation.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22 * MANCE OF THIS SOFTWARE.
23 *
24 * Except as contained in this notice, the name of a copyright holder shall
25 * not be used in advertising or otherwise to promote the sale, use or
26 * other dealings in this Software without prior written authorization of
27 * the copyright holder.
28 *
29 * Authors:
30 * Kristian Høgsberg (krh@bitplanet.net)
31 */
32
33 #include <stdbool.h>
34
35 #include "glapi.h"
36 #include "glxclient.h"
37
38 #include "util/debug.h"
39
40 #ifndef GLX_USE_APPLEGL
41
42 extern struct _glapi_table *__glXNewIndirectAPI(void);
43
44 /*
45 ** All indirect rendering contexts will share the same indirect dispatch table.
46 */
47 static struct _glapi_table *IndirectAPI = NULL;
48
49 static void
50 indirect_destroy_context(struct glx_context *gc)
51 {
52 __glXFreeVertexArrayState(gc);
53
54 free((char *) gc->vendor);
55 free((char *) gc->renderer);
56 free((char *) gc->version);
57 free((char *) gc->extensions);
58 __glFreeAttributeState(gc);
59 free((char *) gc->buf);
60 free((char *) gc->client_state_private);
61 free((char *) gc);
62 }
63
64 static Bool
65 SendMakeCurrentRequest(Display * dpy, GLXContextID gc_id,
66 GLXContextTag gc_tag, GLXDrawable draw,
67 GLXDrawable read, GLXContextTag *out_tag)
68 {
69 xGLXMakeCurrentReply reply;
70 Bool ret;
71 int opcode = __glXSetupForCommand(dpy);
72
73 LockDisplay(dpy);
74
75 if (draw == read) {
76 xGLXMakeCurrentReq *req;
77
78 GetReq(GLXMakeCurrent, req);
79 req->reqType = opcode;
80 req->glxCode = X_GLXMakeCurrent;
81 req->drawable = draw;
82 req->context = gc_id;
83 req->oldContextTag = gc_tag;
84 }
85 else {
86 struct glx_display *priv = __glXInitialize(dpy);
87
88 /* If the server can support the GLX 1.3 version, we should
89 * perfer that. Not only that, some servers support GLX 1.3 but
90 * not the SGI extension.
91 */
92
93 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
94 xGLXMakeContextCurrentReq *req;
95
96 GetReq(GLXMakeContextCurrent, req);
97 req->reqType = opcode;
98 req->glxCode = X_GLXMakeContextCurrent;
99 req->drawable = draw;
100 req->readdrawable = read;
101 req->context = gc_id;
102 req->oldContextTag = gc_tag;
103 }
104 else {
105 xGLXVendorPrivateWithReplyReq *vpreq;
106 xGLXMakeCurrentReadSGIReq *req;
107
108 GetReqExtra(GLXVendorPrivateWithReply,
109 sz_xGLXMakeCurrentReadSGIReq -
110 sz_xGLXVendorPrivateWithReplyReq, vpreq);
111 req = (xGLXMakeCurrentReadSGIReq *) vpreq;
112 req->reqType = opcode;
113 req->glxCode = X_GLXVendorPrivateWithReply;
114 req->vendorCode = X_GLXvop_MakeCurrentReadSGI;
115 req->drawable = draw;
116 req->readable = read;
117 req->context = gc_id;
118 req->oldContextTag = gc_tag;
119 }
120 }
121
122 ret = _XReply(dpy, (xReply *) &reply, 0, False);
123
124 if (out_tag)
125 *out_tag = reply.contextTag;
126
127 UnlockDisplay(dpy);
128 SyncHandle();
129
130 return ret;
131 }
132
133 static int
134 indirect_bind_context(struct glx_context *gc, struct glx_context *old,
135 GLXDrawable draw, GLXDrawable read)
136 {
137 GLXContextTag tag;
138 Display *dpy = gc->psc->dpy;
139 Bool sent;
140
141 if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) {
142 tag = old->currentContextTag;
143 old->currentContextTag = 0;
144 } else {
145 tag = 0;
146 }
147
148 sent = SendMakeCurrentRequest(dpy, gc->xid, tag, draw, read,
149 &gc->currentContextTag);
150
151 if (!IndirectAPI)
152 IndirectAPI = __glXNewIndirectAPI();
153 _glapi_set_dispatch(IndirectAPI);
154
155 return !sent;
156 }
157
158 static void
159 indirect_unbind_context(struct glx_context *gc, struct glx_context *new)
160 {
161 Display *dpy = gc->psc->dpy;
162
163 if (gc == new)
164 return;
165
166 /* We are either switching to no context, away from an indirect
167 * context to a direct context or from one dpy to another and have
168 * to send a request to the dpy to unbind the previous context.
169 */
170 if (!new || new->isDirect || new->psc->dpy != dpy) {
171 SendMakeCurrentRequest(dpy, None, gc->currentContextTag, None, None,
172 NULL);
173 gc->currentContextTag = 0;
174 }
175 }
176
177 static void
178 indirect_wait_gl(struct glx_context *gc)
179 {
180 xGLXWaitGLReq *req;
181 Display *dpy = gc->currentDpy;
182
183 /* Flush any pending commands out */
184 __glXFlushRenderBuffer(gc, gc->pc);
185
186 /* Send the glXWaitGL request */
187 LockDisplay(dpy);
188 GetReq(GLXWaitGL, req);
189 req->reqType = gc->majorOpcode;
190 req->glxCode = X_GLXWaitGL;
191 req->contextTag = gc->currentContextTag;
192 UnlockDisplay(dpy);
193 SyncHandle();
194 }
195
196 static void
197 indirect_wait_x(struct glx_context *gc)
198 {
199 xGLXWaitXReq *req;
200 Display *dpy = gc->currentDpy;
201
202 /* Flush any pending commands out */
203 __glXFlushRenderBuffer(gc, gc->pc);
204
205 LockDisplay(dpy);
206 GetReq(GLXWaitX, req);
207 req->reqType = gc->majorOpcode;
208 req->glxCode = X_GLXWaitX;
209 req->contextTag = gc->currentContextTag;
210 UnlockDisplay(dpy);
211 SyncHandle();
212 }
213
214 static void
215 indirect_use_x_font(struct glx_context *gc,
216 Font font, int first, int count, int listBase)
217 {
218 xGLXUseXFontReq *req;
219 Display *dpy = gc->currentDpy;
220
221 /* Flush any pending commands out */
222 __glXFlushRenderBuffer(gc, gc->pc);
223
224 /* Send the glXUseFont request */
225 LockDisplay(dpy);
226 GetReq(GLXUseXFont, req);
227 req->reqType = gc->majorOpcode;
228 req->glxCode = X_GLXUseXFont;
229 req->contextTag = gc->currentContextTag;
230 req->font = font;
231 req->first = first;
232 req->count = count;
233 req->listBase = listBase;
234 UnlockDisplay(dpy);
235 SyncHandle();
236 }
237
238 static void
239 indirect_bind_tex_image(Display * dpy,
240 GLXDrawable drawable,
241 int buffer, const int *attrib_list)
242 {
243 xGLXVendorPrivateReq *req;
244 struct glx_context *gc = __glXGetCurrentContext();
245 CARD32 *drawable_ptr;
246 INT32 *buffer_ptr;
247 CARD32 *num_attrib_ptr;
248 CARD32 *attrib_ptr;
249 CARD8 opcode;
250 unsigned int i;
251
252 i = 0;
253 if (attrib_list) {
254 while (attrib_list[i * 2] != None)
255 i++;
256 }
257
258 opcode = __glXSetupForCommand(dpy);
259 if (!opcode)
260 return;
261
262 LockDisplay(dpy);
263 GetReqExtra(GLXVendorPrivate, 12 + 8 * i, req);
264 req->reqType = opcode;
265 req->glxCode = X_GLXVendorPrivate;
266 req->vendorCode = X_GLXvop_BindTexImageEXT;
267 req->contextTag = gc->currentContextTag;
268
269 drawable_ptr = (CARD32 *) (req + 1);
270 buffer_ptr = (INT32 *) (drawable_ptr + 1);
271 num_attrib_ptr = (CARD32 *) (buffer_ptr + 1);
272 attrib_ptr = (CARD32 *) (num_attrib_ptr + 1);
273
274 *drawable_ptr = drawable;
275 *buffer_ptr = buffer;
276 *num_attrib_ptr = (CARD32) i;
277
278 i = 0;
279 if (attrib_list) {
280 while (attrib_list[i * 2] != None) {
281 *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 0];
282 *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 1];
283 i++;
284 }
285 }
286
287 UnlockDisplay(dpy);
288 SyncHandle();
289 }
290
291 static void
292 indirect_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
293 {
294 xGLXVendorPrivateReq *req;
295 struct glx_context *gc = __glXGetCurrentContext();
296 CARD32 *drawable_ptr;
297 INT32 *buffer_ptr;
298 CARD8 opcode;
299
300 opcode = __glXSetupForCommand(dpy);
301 if (!opcode)
302 return;
303
304 LockDisplay(dpy);
305 GetReqExtra(GLXVendorPrivate, sizeof(CARD32) + sizeof(INT32), req);
306 req->reqType = opcode;
307 req->glxCode = X_GLXVendorPrivate;
308 req->vendorCode = X_GLXvop_ReleaseTexImageEXT;
309 req->contextTag = gc->currentContextTag;
310
311 drawable_ptr = (CARD32 *) (req + 1);
312 buffer_ptr = (INT32 *) (drawable_ptr + 1);
313
314 *drawable_ptr = drawable;
315 *buffer_ptr = buffer;
316
317 UnlockDisplay(dpy);
318 SyncHandle();
319 }
320
321 static const struct glx_context_vtable indirect_context_vtable = {
322 .destroy = indirect_destroy_context,
323 .bind = indirect_bind_context,
324 .unbind = indirect_unbind_context,
325 .wait_gl = indirect_wait_gl,
326 .wait_x = indirect_wait_x,
327 .use_x_font = indirect_use_x_font,
328 .bind_tex_image = indirect_bind_tex_image,
329 .release_tex_image = indirect_release_tex_image,
330 .get_proc_address = NULL,
331 };
332
333 /**
334 * \todo Eliminate \c __glXInitVertexArrayState. Replace it with a new
335 * function called \c __glXAllocateClientState that allocates the memory and
336 * does all the initialization (including the pixel pack / unpack).
337 *
338 * \note
339 * This function is \b not the place to validate the context creation
340 * parameters. It is just the allocator for the \c glx_context.
341 */
342 _X_HIDDEN struct glx_context *
343 indirect_create_context(struct glx_screen *psc,
344 struct glx_config *mode,
345 struct glx_context *shareList, int renderType)
346 {
347 struct glx_context *gc;
348 int bufSize;
349 CARD8 opcode;
350 __GLXattribute *state;
351
352 opcode = __glXSetupForCommand(psc->dpy);
353 if (!opcode) {
354 return NULL;
355 }
356
357 /* Allocate our context record */
358 gc = calloc(1, sizeof *gc);
359 if (!gc) {
360 /* Out of memory */
361 return NULL;
362 }
363
364 glx_context_init(gc, psc, mode);
365 gc->isDirect = GL_FALSE;
366 gc->vtable = &indirect_context_vtable;
367 state = calloc(1, sizeof(struct __GLXattributeRec));
368 gc->renderType = renderType;
369
370 if (state == NULL) {
371 /* Out of memory */
372 free(gc);
373 return NULL;
374 }
375 gc->client_state_private = state;
376 state->NoDrawArraysProtocol = env_var_as_boolean("LIBGL_NO_DRAWARRAYS", false);
377
378 /*
379 ** Create a temporary buffer to hold GLX rendering commands. The size
380 ** of the buffer is selected so that the maximum number of GLX rendering
381 ** commands can fit in a single X packet and still have room in the X
382 ** packet for the GLXRenderReq header.
383 */
384
385 bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq;
386 gc->buf = malloc(bufSize);
387 if (!gc->buf) {
388 free(gc->client_state_private);
389 free(gc);
390 return NULL;
391 }
392 gc->bufSize = bufSize;
393
394 /* Fill in the new context */
395 gc->renderMode = GL_RENDER;
396
397 state->storePack.alignment = 4;
398 state->storeUnpack.alignment = 4;
399
400 gc->attributes.stackPointer = &gc->attributes.stack[0];
401
402 gc->pc = gc->buf;
403 gc->bufEnd = gc->buf + bufSize;
404 gc->isDirect = GL_FALSE;
405 if (__glXDebug) {
406 /*
407 ** Set limit register so that there will be one command per packet
408 */
409 gc->limit = gc->buf;
410 }
411 else {
412 gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
413 }
414 gc->majorOpcode = opcode;
415
416 /*
417 ** Constrain the maximum drawing command size allowed to be
418 ** transfered using the X_GLXRender protocol request. First
419 ** constrain by a software limit, then constrain by the protocl
420 ** limit.
421 */
422 if (bufSize > __GLX_RENDER_CMD_SIZE_LIMIT) {
423 bufSize = __GLX_RENDER_CMD_SIZE_LIMIT;
424 }
425 if (bufSize > __GLX_MAX_RENDER_CMD_SIZE) {
426 bufSize = __GLX_MAX_RENDER_CMD_SIZE;
427 }
428 gc->maxSmallRenderCommandSize = bufSize;
429
430
431 return gc;
432 }
433
434 _X_HIDDEN struct glx_context *
435 indirect_create_context_attribs(struct glx_screen *base,
436 struct glx_config *config_base,
437 struct glx_context *shareList,
438 unsigned num_attribs,
439 const uint32_t *attribs,
440 unsigned *error)
441 {
442 int renderType = GLX_RGBA_TYPE;
443 unsigned i;
444
445 /* The error parameter is only used on the server so that correct GLX
446 * protocol errors can be generated. On the client, it can be ignored.
447 */
448 (void) error;
449
450 /* All of the attribute validation for indirect contexts is handled on the
451 * server, so there's not much to do here. Still, we need to parse the
452 * attributes to correctly set renderType.
453 */
454 for (i = 0; i < num_attribs; i++) {
455 if (attribs[i * 2] == GLX_RENDER_TYPE)
456 renderType = attribs[i * 2 + 1];
457 }
458
459 return indirect_create_context(base, config_base, shareList, renderType);
460 }
461
462 static const struct glx_screen_vtable indirect_screen_vtable = {
463 .create_context = indirect_create_context,
464 .create_context_attribs = indirect_create_context_attribs,
465 .query_renderer_integer = NULL,
466 .query_renderer_string = NULL,
467 };
468
469 _X_HIDDEN struct glx_screen *
470 indirect_create_screen(int screen, struct glx_display * priv)
471 {
472 struct glx_screen *psc;
473
474 psc = calloc(1, sizeof *psc);
475 if (psc == NULL)
476 return NULL;
477
478 glx_screen_init(psc, screen, priv);
479 psc->vtable = &indirect_screen_vtable;
480
481 return psc;
482 }
483
484 #endif