glx: Prepare the DRI backends for GLX_EXT_no_config_context
[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, CARD8 opcode,
66 GLXContextID gc_id, GLXContextTag gc_tag,
67 GLXDrawable draw, GLXDrawable read,
68 GLXContextTag *out_tag)
69 {
70 xGLXMakeCurrentReply reply;
71 Bool ret;
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 int opcode = __glXSetupForCommand(dpy);
140 Bool sent;
141
142 if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) {
143 tag = old->currentContextTag;
144 old->currentContextTag = 0;
145 } else {
146 tag = 0;
147 }
148
149 sent = SendMakeCurrentRequest(dpy, opcode, gc->xid, tag, draw, read,
150 &gc->currentContextTag);
151
152 if (!IndirectAPI)
153 IndirectAPI = __glXNewIndirectAPI();
154 _glapi_set_dispatch(IndirectAPI);
155
156 return !sent;
157 }
158
159 static void
160 indirect_unbind_context(struct glx_context *gc, struct glx_context *new)
161 {
162 Display *dpy = gc->psc->dpy;
163 int opcode = __glXSetupForCommand(dpy);
164
165 if (gc == new)
166 return;
167
168 /* We are either switching to no context, away from an indirect
169 * context to a direct context or from one dpy to another and have
170 * to send a request to the dpy to unbind the previous context.
171 */
172 if (!new || new->isDirect || new->psc->dpy != dpy) {
173 SendMakeCurrentRequest(dpy, opcode, None,
174 gc->currentContextTag, None, None, NULL);
175 gc->currentContextTag = 0;
176 }
177 }
178
179 static void
180 indirect_wait_gl(struct glx_context *gc)
181 {
182 xGLXWaitGLReq *req;
183 Display *dpy = gc->currentDpy;
184
185 /* Flush any pending commands out */
186 __glXFlushRenderBuffer(gc, gc->pc);
187
188 /* Send the glXWaitGL request */
189 LockDisplay(dpy);
190 GetReq(GLXWaitGL, req);
191 req->reqType = gc->majorOpcode;
192 req->glxCode = X_GLXWaitGL;
193 req->contextTag = gc->currentContextTag;
194 UnlockDisplay(dpy);
195 SyncHandle();
196 }
197
198 static void
199 indirect_wait_x(struct glx_context *gc)
200 {
201 xGLXWaitXReq *req;
202 Display *dpy = gc->currentDpy;
203
204 /* Flush any pending commands out */
205 __glXFlushRenderBuffer(gc, gc->pc);
206
207 LockDisplay(dpy);
208 GetReq(GLXWaitX, req);
209 req->reqType = gc->majorOpcode;
210 req->glxCode = X_GLXWaitX;
211 req->contextTag = gc->currentContextTag;
212 UnlockDisplay(dpy);
213 SyncHandle();
214 }
215
216 static void
217 indirect_use_x_font(struct glx_context *gc,
218 Font font, int first, int count, int listBase)
219 {
220 xGLXUseXFontReq *req;
221 Display *dpy = gc->currentDpy;
222
223 /* Flush any pending commands out */
224 __glXFlushRenderBuffer(gc, gc->pc);
225
226 /* Send the glXUseFont request */
227 LockDisplay(dpy);
228 GetReq(GLXUseXFont, req);
229 req->reqType = gc->majorOpcode;
230 req->glxCode = X_GLXUseXFont;
231 req->contextTag = gc->currentContextTag;
232 req->font = font;
233 req->first = first;
234 req->count = count;
235 req->listBase = listBase;
236 UnlockDisplay(dpy);
237 SyncHandle();
238 }
239
240 static void
241 indirect_bind_tex_image(Display * dpy,
242 GLXDrawable drawable,
243 int buffer, const int *attrib_list)
244 {
245 xGLXVendorPrivateReq *req;
246 struct glx_context *gc = __glXGetCurrentContext();
247 CARD32 *drawable_ptr;
248 INT32 *buffer_ptr;
249 CARD32 *num_attrib_ptr;
250 CARD32 *attrib_ptr;
251 CARD8 opcode;
252 unsigned int i;
253
254 i = 0;
255 if (attrib_list) {
256 while (attrib_list[i * 2] != None)
257 i++;
258 }
259
260 opcode = __glXSetupForCommand(dpy);
261 if (!opcode)
262 return;
263
264 LockDisplay(dpy);
265 GetReqExtra(GLXVendorPrivate, 12 + 8 * i, req);
266 req->reqType = opcode;
267 req->glxCode = X_GLXVendorPrivate;
268 req->vendorCode = X_GLXvop_BindTexImageEXT;
269 req->contextTag = gc->currentContextTag;
270
271 drawable_ptr = (CARD32 *) (req + 1);
272 buffer_ptr = (INT32 *) (drawable_ptr + 1);
273 num_attrib_ptr = (CARD32 *) (buffer_ptr + 1);
274 attrib_ptr = (CARD32 *) (num_attrib_ptr + 1);
275
276 *drawable_ptr = drawable;
277 *buffer_ptr = buffer;
278 *num_attrib_ptr = (CARD32) i;
279
280 i = 0;
281 if (attrib_list) {
282 while (attrib_list[i * 2] != None) {
283 *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 0];
284 *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 1];
285 i++;
286 }
287 }
288
289 UnlockDisplay(dpy);
290 SyncHandle();
291 }
292
293 static void
294 indirect_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
295 {
296 xGLXVendorPrivateReq *req;
297 struct glx_context *gc = __glXGetCurrentContext();
298 CARD32 *drawable_ptr;
299 INT32 *buffer_ptr;
300 CARD8 opcode;
301
302 opcode = __glXSetupForCommand(dpy);
303 if (!opcode)
304 return;
305
306 LockDisplay(dpy);
307 GetReqExtra(GLXVendorPrivate, sizeof(CARD32) + sizeof(INT32), req);
308 req->reqType = opcode;
309 req->glxCode = X_GLXVendorPrivate;
310 req->vendorCode = X_GLXvop_ReleaseTexImageEXT;
311 req->contextTag = gc->currentContextTag;
312
313 drawable_ptr = (CARD32 *) (req + 1);
314 buffer_ptr = (INT32 *) (drawable_ptr + 1);
315
316 *drawable_ptr = drawable;
317 *buffer_ptr = buffer;
318
319 UnlockDisplay(dpy);
320 SyncHandle();
321 }
322
323 static const struct glx_context_vtable indirect_context_vtable = {
324 .destroy = indirect_destroy_context,
325 .bind = indirect_bind_context,
326 .unbind = indirect_unbind_context,
327 .wait_gl = indirect_wait_gl,
328 .wait_x = indirect_wait_x,
329 .use_x_font = indirect_use_x_font,
330 .bind_tex_image = indirect_bind_tex_image,
331 .release_tex_image = indirect_release_tex_image,
332 .get_proc_address = NULL,
333 };
334
335 /**
336 * \todo Eliminate \c __glXInitVertexArrayState. Replace it with a new
337 * function called \c __glXAllocateClientState that allocates the memory and
338 * does all the initialization (including the pixel pack / unpack).
339 *
340 * \note
341 * This function is \b not the place to validate the context creation
342 * parameters. It is just the allocator for the \c glx_context.
343 */
344 _X_HIDDEN struct glx_context *
345 indirect_create_context(struct glx_screen *psc,
346 struct glx_config *mode,
347 struct glx_context *shareList, int renderType)
348 {
349 struct glx_context *gc;
350 int bufSize;
351 CARD8 opcode;
352 __GLXattribute *state;
353
354 opcode = __glXSetupForCommand(psc->dpy);
355 if (!opcode) {
356 return NULL;
357 }
358
359 /* Allocate our context record */
360 gc = calloc(1, sizeof *gc);
361 if (!gc) {
362 /* Out of memory */
363 return NULL;
364 }
365
366 glx_context_init(gc, psc, mode);
367 gc->isDirect = GL_FALSE;
368 gc->vtable = &indirect_context_vtable;
369 state = calloc(1, sizeof(struct __GLXattributeRec));
370 gc->renderType = renderType;
371
372 if (state == NULL) {
373 /* Out of memory */
374 free(gc);
375 return NULL;
376 }
377 gc->client_state_private = state;
378 state->NoDrawArraysProtocol = env_var_as_boolean("LIBGL_NO_DRAWARRAYS", false);
379
380 /*
381 ** Create a temporary buffer to hold GLX rendering commands. The size
382 ** of the buffer is selected so that the maximum number of GLX rendering
383 ** commands can fit in a single X packet and still have room in the X
384 ** packet for the GLXRenderReq header.
385 */
386
387 bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq;
388 gc->buf = malloc(bufSize);
389 if (!gc->buf) {
390 free(gc->client_state_private);
391 free(gc);
392 return NULL;
393 }
394 gc->bufSize = bufSize;
395
396 /* Fill in the new context */
397 gc->renderMode = GL_RENDER;
398
399 state->storePack.alignment = 4;
400 state->storeUnpack.alignment = 4;
401
402 gc->attributes.stackPointer = &gc->attributes.stack[0];
403
404 /*
405 ** PERFORMANCE NOTE: A mode dependent fill image can speed things up.
406 */
407 gc->fillImage = __glFillImage;
408 gc->pc = gc->buf;
409 gc->bufEnd = gc->buf + bufSize;
410 gc->isDirect = GL_FALSE;
411 if (__glXDebug) {
412 /*
413 ** Set limit register so that there will be one command per packet
414 */
415 gc->limit = gc->buf;
416 }
417 else {
418 gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
419 }
420 gc->majorOpcode = opcode;
421
422 /*
423 ** Constrain the maximum drawing command size allowed to be
424 ** transfered using the X_GLXRender protocol request. First
425 ** constrain by a software limit, then constrain by the protocl
426 ** limit.
427 */
428 if (bufSize > __GLX_RENDER_CMD_SIZE_LIMIT) {
429 bufSize = __GLX_RENDER_CMD_SIZE_LIMIT;
430 }
431 if (bufSize > __GLX_MAX_RENDER_CMD_SIZE) {
432 bufSize = __GLX_MAX_RENDER_CMD_SIZE;
433 }
434 gc->maxSmallRenderCommandSize = bufSize;
435
436
437 return gc;
438 }
439
440 _X_HIDDEN struct glx_context *
441 indirect_create_context_attribs(struct glx_screen *base,
442 struct glx_config *config_base,
443 struct glx_context *shareList,
444 unsigned num_attribs,
445 const uint32_t *attribs,
446 unsigned *error)
447 {
448 int renderType = GLX_RGBA_TYPE;
449 unsigned i;
450
451 /* The error parameter is only used on the server so that correct GLX
452 * protocol errors can be generated. On the client, it can be ignored.
453 */
454 (void) error;
455
456 /* All of the attribute validation for indirect contexts is handled on the
457 * server, so there's not much to do here. Still, we need to parse the
458 * attributes to correctly set renderType.
459 */
460 for (i = 0; i < num_attribs; i++) {
461 if (attribs[i * 2] == GLX_RENDER_TYPE)
462 renderType = attribs[i * 2 + 1];
463 }
464
465 return indirect_create_context(base, config_base, shareList, renderType);
466 }
467
468 static const struct glx_screen_vtable indirect_screen_vtable = {
469 .create_context = indirect_create_context,
470 .create_context_attribs = indirect_create_context_attribs,
471 .query_renderer_integer = NULL,
472 .query_renderer_string = NULL,
473 };
474
475 _X_HIDDEN struct glx_screen *
476 indirect_create_screen(int screen, struct glx_display * priv)
477 {
478 struct glx_screen *psc;
479
480 psc = calloc(1, sizeof *psc);
481 if (psc == NULL)
482 return NULL;
483
484 glx_screen_init(psc, screen, priv);
485 psc->vtable = &indirect_screen_vtable;
486
487 return psc;
488 }
489
490 #endif