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