• 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 #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
__glFreeAttributeState(struct glx_context * gc)50 __glFreeAttributeState(struct glx_context * gc)
51 {
52    __GLXattribute *sp, **spp;
53 
54    for (spp = &gc->attributes.stack[0];
55         spp < &gc->attributes.stack[__GL_CLIENT_ATTRIB_STACK_DEPTH]; spp++) {
56       sp = *spp;
57       if (sp) {
58          free((char *) sp);
59       }
60       else {
61          break;
62       }
63    }
64 }
65 
66 static void
indirect_destroy_context(struct glx_context * gc)67 indirect_destroy_context(struct glx_context *gc)
68 {
69    __glXFreeVertexArrayState(gc);
70 
71    free((char *) gc->vendor);
72    free((char *) gc->renderer);
73    free((char *) gc->version);
74    free((char *) gc->extensions);
75    __glFreeAttributeState(gc);
76    free((char *) gc->buf);
77    free((char *) gc->client_state_private);
78    free((char *) gc);
79 }
80 
81 static Bool
SendMakeCurrentRequest(Display * dpy,GLXContextID gc_id,GLXContextTag gc_tag,GLXDrawable draw,GLXDrawable read,GLXContextTag * out_tag)82 SendMakeCurrentRequest(Display * dpy, GLXContextID gc_id,
83                        GLXContextTag gc_tag, GLXDrawable draw,
84                        GLXDrawable read, GLXContextTag *out_tag)
85 {
86    xGLXMakeCurrentReply reply;
87    Bool ret;
88    int opcode = __glXSetupForCommand(dpy);
89 
90    LockDisplay(dpy);
91 
92    if (draw == read) {
93       xGLXMakeCurrentReq *req;
94 
95       GetReq(GLXMakeCurrent, req);
96       req->reqType = opcode;
97       req->glxCode = X_GLXMakeCurrent;
98       req->drawable = draw;
99       req->context = gc_id;
100       req->oldContextTag = gc_tag;
101    }
102    else {
103       struct glx_display *priv = __glXInitialize(dpy);
104 
105       /* If the server can support the GLX 1.3 version, we should
106        * perfer that.  Not only that, some servers support GLX 1.3 but
107        * not the SGI extension.
108        */
109 
110       if (priv->minorVersion >= 3) {
111          xGLXMakeContextCurrentReq *req;
112 
113          GetReq(GLXMakeContextCurrent, req);
114          req->reqType = opcode;
115          req->glxCode = X_GLXMakeContextCurrent;
116          req->drawable = draw;
117          req->readdrawable = read;
118          req->context = gc_id;
119          req->oldContextTag = gc_tag;
120       }
121       else {
122          xGLXVendorPrivateWithReplyReq *vpreq;
123          xGLXMakeCurrentReadSGIReq *req;
124 
125          GetReqExtra(GLXVendorPrivateWithReply,
126                      sz_xGLXMakeCurrentReadSGIReq -
127                      sz_xGLXVendorPrivateWithReplyReq, vpreq);
128          req = (xGLXMakeCurrentReadSGIReq *) vpreq;
129          req->reqType = opcode;
130          req->glxCode = X_GLXVendorPrivateWithReply;
131          req->vendorCode = X_GLXvop_MakeCurrentReadSGI;
132          req->drawable = draw;
133          req->readable = read;
134          req->context = gc_id;
135          req->oldContextTag = gc_tag;
136       }
137    }
138 
139    ret = _XReply(dpy, (xReply *) &reply, 0, False);
140 
141    if (out_tag)
142       *out_tag = reply.contextTag;
143 
144    UnlockDisplay(dpy);
145    SyncHandle();
146 
147    return ret;
148 }
149 
150 static int
indirect_bind_context(struct glx_context * gc,struct glx_context * old,GLXDrawable draw,GLXDrawable read)151 indirect_bind_context(struct glx_context *gc, struct glx_context *old,
152 		      GLXDrawable draw, GLXDrawable read)
153 {
154    GLXContextTag tag;
155    Display *dpy = gc->psc->dpy;
156    Bool sent;
157 
158    if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) {
159       tag = old->currentContextTag;
160       old->currentContextTag = 0;
161    } else {
162       tag = 0;
163    }
164 
165    sent = SendMakeCurrentRequest(dpy, gc->xid, tag, draw, read,
166 				 &gc->currentContextTag);
167 
168    if (sent) {
169       if (!IndirectAPI)
170          IndirectAPI = __glXNewIndirectAPI();
171       _glapi_set_dispatch(IndirectAPI);
172 
173       /* The indirect vertex array state must to be initialised after we
174        * have setup the context, as it needs to query server attributes.
175        *
176        * At the point this is called gc->currentDpy is not initialized
177        * nor is the thread's current context actually set. Hence the
178        * cleverness before the GetString calls.
179        */
180       __GLXattribute *state = gc->client_state_private;
181       if (state && state->array_state == NULL) {
182          gc->currentDpy = gc->psc->dpy;
183          __glXSetCurrentContext(gc);
184          __indirect_glGetString(GL_EXTENSIONS);
185          __indirect_glGetString(GL_VERSION);
186          __glXInitVertexArrayState(gc);
187       }
188    }
189 
190    return !sent;
191 }
192 
193 static void
indirect_unbind_context(struct glx_context * gc,struct glx_context * new)194 indirect_unbind_context(struct glx_context *gc, struct glx_context *new)
195 {
196    Display *dpy = gc->psc->dpy;
197 
198    if (gc == new)
199       return;
200 
201    /* We are either switching to no context, away from an indirect
202     * context to a direct context or from one dpy to another and have
203     * to send a request to the dpy to unbind the previous context.
204     */
205    if (!new || new->isDirect || new->psc->dpy != dpy) {
206       SendMakeCurrentRequest(dpy, None, gc->currentContextTag, None, None,
207                              NULL);
208       gc->currentContextTag = 0;
209    }
210 }
211 
212 static void
indirect_wait_gl(struct glx_context * gc)213 indirect_wait_gl(struct glx_context *gc)
214 {
215    xGLXWaitGLReq *req;
216    Display *dpy = gc->currentDpy;
217 
218    /* Flush any pending commands out */
219    __glXFlushRenderBuffer(gc, gc->pc);
220 
221    /* Send the glXWaitGL request */
222    LockDisplay(dpy);
223    GetReq(GLXWaitGL, req);
224    req->reqType = gc->majorOpcode;
225    req->glxCode = X_GLXWaitGL;
226    req->contextTag = gc->currentContextTag;
227    UnlockDisplay(dpy);
228    SyncHandle();
229 }
230 
231 static void
indirect_wait_x(struct glx_context * gc)232 indirect_wait_x(struct glx_context *gc)
233 {
234    xGLXWaitXReq *req;
235    Display *dpy = gc->currentDpy;
236 
237    /* Flush any pending commands out */
238    __glXFlushRenderBuffer(gc, gc->pc);
239 
240    LockDisplay(dpy);
241    GetReq(GLXWaitX, req);
242    req->reqType = gc->majorOpcode;
243    req->glxCode = X_GLXWaitX;
244    req->contextTag = gc->currentContextTag;
245    UnlockDisplay(dpy);
246    SyncHandle();
247 }
248 
249 static const struct glx_context_vtable indirect_context_vtable = {
250    .destroy             = indirect_destroy_context,
251    .bind                = indirect_bind_context,
252    .unbind              = indirect_unbind_context,
253    .wait_gl             = indirect_wait_gl,
254    .wait_x              = indirect_wait_x,
255 };
256 
257 _X_HIDDEN struct glx_context *
indirect_create_context(struct glx_screen * psc,struct glx_config * mode,struct glx_context * shareList,int renderType)258 indirect_create_context(struct glx_screen *psc,
259 			struct glx_config *mode,
260 			struct glx_context *shareList, int renderType)
261 {
262    unsigned error = 0;
263    const uint32_t attribs[] = { GLX_RENDER_TYPE, renderType };
264 
265    return indirect_create_context_attribs(psc, mode, shareList,
266                                           1, attribs, &error);
267 }
268 
269 /**
270  * \todo Eliminate \c __glXInitVertexArrayState.  Replace it with a new
271  * function called \c __glXAllocateClientState that allocates the memory and
272  * does all the initialization (including the pixel pack / unpack).
273  */
274 _X_HIDDEN struct glx_context *
indirect_create_context_attribs(struct glx_screen * psc,struct glx_config * mode,struct glx_context * shareList,unsigned num_attribs,const uint32_t * attribs,unsigned * error)275 indirect_create_context_attribs(struct glx_screen *psc,
276 				struct glx_config *mode,
277 				struct glx_context *shareList,
278 				unsigned num_attribs,
279 				const uint32_t *attribs,
280 				unsigned *error)
281 {
282    struct glx_context *gc;
283    int bufSize;
284    CARD8 opcode;
285    __GLXattribute *state;
286    int i, renderType = GLX_RGBA_TYPE;
287    uint32_t mask = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
288    uint32_t major = 1;
289    uint32_t minor = 0;
290 
291    opcode = __glXSetupForCommand(psc->dpy);
292    if (!opcode) {
293       return NULL;
294    }
295 
296    for (i = 0; i < num_attribs; i++) {
297       uint32_t attr = attribs[i*2], val = attribs[i*2 + 1];
298 
299       if (attr == GLX_RENDER_TYPE)
300          renderType = val;
301       if (attr == GLX_CONTEXT_PROFILE_MASK_ARB)
302          mask = val;
303       if (attr == GLX_CONTEXT_MAJOR_VERSION_ARB)
304          major = val;
305       if (attr == GLX_CONTEXT_MINOR_VERSION_ARB)
306          minor = val;
307    }
308 
309    /* We have no indirect support for core or ES contexts, and our compat
310     * context support is limited to GL 1.4.
311     */
312    if (mask != GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ||
313        major != 1 ||
314        minor > 4) {
315       return NULL;
316    }
317 
318    /* We can't share with a direct context */
319    if (shareList && shareList->isDirect)
320       return NULL;
321 
322    /* Allocate our context record */
323    gc = calloc(1, sizeof *gc);
324    if (!gc) {
325       /* Out of memory */
326       return NULL;
327    }
328 
329    glx_context_init(gc, psc, mode);
330    gc->isDirect = GL_FALSE;
331    gc->vtable = &indirect_context_vtable;
332    state = calloc(1, sizeof(struct __GLXattributeRec));
333    gc->renderType = renderType;
334 
335    if (state == NULL) {
336       /* Out of memory */
337       free(gc);
338       return NULL;
339    }
340    gc->client_state_private = state;
341    state->NoDrawArraysProtocol = env_var_as_boolean("LIBGL_NO_DRAWARRAYS", false);
342 
343    /*
344     ** Create a temporary buffer to hold GLX rendering commands.  The size
345     ** of the buffer is selected so that the maximum number of GLX rendering
346     ** commands can fit in a single X packet and still have room in the X
347     ** packet for the GLXRenderReq header.
348     */
349 
350    bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq;
351    gc->buf = malloc(bufSize);
352    if (!gc->buf) {
353       free(gc->client_state_private);
354       free(gc);
355       return NULL;
356    }
357    gc->bufSize = bufSize;
358 
359    /* Fill in the new context */
360    gc->renderMode = GL_RENDER;
361 
362    state->storePack.alignment = 4;
363    state->storeUnpack.alignment = 4;
364 
365    gc->attributes.stackPointer = &gc->attributes.stack[0];
366 
367    gc->pc = gc->buf;
368    gc->bufEnd = gc->buf + bufSize;
369    gc->isDirect = GL_FALSE;
370    if (__glXDebug) {
371       /*
372        ** Set limit register so that there will be one command per packet
373        */
374       gc->limit = gc->buf;
375    }
376    else {
377       gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
378    }
379    gc->majorOpcode = opcode;
380 
381    /*
382     ** Constrain the maximum drawing command size allowed to be
383     ** transferred using the X_GLXRender protocol request.  First
384     ** constrain by a software limit, then constrain by the protocol
385     ** limit.
386     */
387    gc->maxSmallRenderCommandSize = MIN3(bufSize, __GLX_RENDER_CMD_SIZE_LIMIT,
388                                         __GLX_MAX_RENDER_CMD_SIZE);
389 
390 
391    return gc;
392 }
393 
394 static const struct glx_screen_vtable indirect_screen_vtable = {
395    .create_context         = indirect_create_context,
396    .create_context_attribs = indirect_create_context_attribs,
397    .query_renderer_integer = NULL,
398    .query_renderer_string  = NULL,
399 };
400 
401 _X_HIDDEN struct glx_screen *
indirect_create_screen(int screen,struct glx_display * priv)402 indirect_create_screen(int screen, struct glx_display * priv)
403 {
404    struct glx_screen *psc;
405 
406    psc = calloc(1, sizeof *psc);
407    if (psc == NULL)
408       return NULL;
409 
410    glx_screen_init(psc, screen, priv);
411    psc->vtable = &indirect_screen_vtable;
412 
413    return psc;
414 }
415 
416 #endif
417