xref: /third_party/mesa3d/src/glx/indirect_glx.c (revision bf215546)
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
42extern struct _glapi_table *__glXNewIndirectAPI(void);
43
44/*
45** All indirect rendering contexts will share the same indirect dispatch table.
46*/
47static struct _glapi_table *IndirectAPI = NULL;
48
49static void
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
66static void
67indirect_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
81static Bool
82SendMakeCurrentRequest(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
150static int
151indirect_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
193static void
194indirect_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
212static void
213indirect_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
231static void
232indirect_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
249static 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 *
258indirect_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 *
275indirect_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
394static 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 *
402indirect_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