• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
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 (!IndirectAPI)
152       IndirectAPI = __glXNewIndirectAPI();
153    _glapi_set_dispatch(IndirectAPI);
154 
155    return !sent;
156 }
157 
158 static void
indirect_unbind_context(struct glx_context * gc,struct glx_context * new)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
indirect_wait_gl(struct glx_context * gc)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
indirect_wait_x(struct glx_context * gc)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
indirect_use_x_font(struct glx_context * gc,Font font,int first,int count,int listBase)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
indirect_bind_tex_image(Display * dpy,GLXDrawable drawable,int buffer,const int * attrib_list)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
indirect_release_tex_image(Display * dpy,GLXDrawable drawable,int buffer)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 *
indirect_create_context(struct glx_screen * psc,struct glx_config * mode,struct glx_context * shareList,int renderType)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    /*
403     ** PERFORMANCE NOTE: A mode dependent fill image can speed things up.
404     */
405    gc->fillImage = __glFillImage;
406    gc->pc = gc->buf;
407    gc->bufEnd = gc->buf + bufSize;
408    gc->isDirect = GL_FALSE;
409    if (__glXDebug) {
410       /*
411        ** Set limit register so that there will be one command per packet
412        */
413       gc->limit = gc->buf;
414    }
415    else {
416       gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
417    }
418    gc->majorOpcode = opcode;
419 
420    /*
421     ** Constrain the maximum drawing command size allowed to be
422     ** transfered using the X_GLXRender protocol request.  First
423     ** constrain by a software limit, then constrain by the protocl
424     ** limit.
425     */
426    if (bufSize > __GLX_RENDER_CMD_SIZE_LIMIT) {
427       bufSize = __GLX_RENDER_CMD_SIZE_LIMIT;
428    }
429    if (bufSize > __GLX_MAX_RENDER_CMD_SIZE) {
430       bufSize = __GLX_MAX_RENDER_CMD_SIZE;
431    }
432    gc->maxSmallRenderCommandSize = bufSize;
433 
434 
435    return gc;
436 }
437 
438 _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)439 indirect_create_context_attribs(struct glx_screen *base,
440 				struct glx_config *config_base,
441 				struct glx_context *shareList,
442 				unsigned num_attribs,
443 				const uint32_t *attribs,
444 				unsigned *error)
445 {
446    int renderType = GLX_RGBA_TYPE;
447    unsigned i;
448 
449    /* The error parameter is only used on the server so that correct GLX
450     * protocol errors can be generated.  On the client, it can be ignored.
451     */
452    (void) error;
453 
454    /* All of the attribute validation for indirect contexts is handled on the
455     * server, so there's not much to do here. Still, we need to parse the
456     * attributes to correctly set renderType.
457     */
458    for (i = 0; i < num_attribs; i++) {
459       if (attribs[i * 2] == GLX_RENDER_TYPE)
460          renderType = attribs[i * 2 + 1];
461    }
462 
463    return indirect_create_context(base, config_base, shareList, renderType);
464 }
465 
466 static const struct glx_screen_vtable indirect_screen_vtable = {
467    .create_context         = indirect_create_context,
468    .create_context_attribs = indirect_create_context_attribs,
469    .query_renderer_integer = NULL,
470    .query_renderer_string  = NULL,
471 };
472 
473 _X_HIDDEN struct glx_screen *
indirect_create_screen(int screen,struct glx_display * priv)474 indirect_create_screen(int screen, struct glx_display * priv)
475 {
476    struct glx_screen *psc;
477 
478    psc = calloc(1, sizeof *psc);
479    if (psc == NULL)
480       return NULL;
481 
482    glx_screen_init(psc, screen, priv);
483    psc->vtable = &indirect_screen_vtable;
484 
485    return psc;
486 }
487 
488 #endif
489