indirect_glx.c revision 6849916170c0275c13510251a7b217c20f2b993e
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 "glapi.h"
34#include "glxclient.h"
35
36extern struct _glapi_table *__glXNewIndirectAPI(void);
37
38/*
39** All indirect rendering contexts will share the same indirect dispatch table.
40*/
41static struct _glapi_table *IndirectAPI = NULL;
42
43static void
44indirect_destroy_context(struct glx_context *gc)
45{
46   if (!gc->imported && gc->xid)
47      glx_send_destroy_context(gc->psc->dpy, gc->xid);
48
49   __glXFreeVertexArrayState(gc);
50
51   if (gc->vendor)
52      XFree((char *) gc->vendor);
53   if (gc->renderer)
54      XFree((char *) gc->renderer);
55   if (gc->version)
56      XFree((char *) gc->version);
57   if (gc->extensions)
58      XFree((char *) gc->extensions);
59   __glFreeAttributeState(gc);
60   XFree((char *) gc->buf);
61   Xfree((char *) gc->client_state_private);
62   XFree((char *) gc);
63}
64
65static Bool
66SendMakeCurrentRequest(Display * dpy, CARD8 opcode,
67                       GLXContextID gc_id, GLXContextTag gc_tag,
68                       GLXDrawable draw, GLXDrawable read,
69                       xGLXMakeCurrentReply * reply)
70{
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   UnlockDisplay(dpy);
125   SyncHandle();
126
127   return ret;
128}
129
130static int
131indirect_bind_context(struct glx_context *gc, struct glx_context *old,
132		      GLXDrawable draw, GLXDrawable read)
133{
134   xGLXMakeCurrentReply reply;
135   GLXContextTag tag;
136   __GLXattribute *state;
137   Display *dpy = gc->psc->dpy;
138   int opcode = __glXSetupForCommand(dpy);
139
140   if (old && !old->isDirect && old->psc->dpy == dpy)
141      tag = old->currentContextTag;
142   else
143      tag = None;
144
145   SendMakeCurrentRequest(dpy, opcode, gc->xid, tag, draw, read, &reply);
146
147   if (!IndirectAPI)
148      IndirectAPI = __glXNewIndirectAPI();
149   _glapi_set_dispatch(IndirectAPI);
150
151   gc->currentContextTag = reply.contextTag;
152   state = gc->client_state_private;
153   if (state->array_state == NULL) {
154      glGetString(GL_EXTENSIONS);
155      glGetString(GL_VERSION);
156      __glXInitVertexArrayState(gc);
157   }
158
159   return Success;
160}
161
162static void
163indirect_unbind_context(struct glx_context *gc, struct glx_context *new)
164{
165   Display *dpy = gc->psc->dpy;
166   int opcode = __glXSetupForCommand(dpy);
167   xGLXMakeCurrentReply reply;
168
169   /* We are either switching to no context, away from a indirect
170    * context to a direct context or from one dpy to another and have
171    * to send a request to the dpy to unbind the previous context.
172    */
173   if (!new || new->isDirect || new->psc->dpy != dpy)
174      SendMakeCurrentRequest(dpy, opcode, None,
175			     gc->currentContextTag, None, None, &reply);
176   gc->currentContextTag = 0;
177}
178
179static void
180indirect_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
198static void
199indirect_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
216static void
217indirect_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
240static void
241indirect_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
293static void
294indirect_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
323static const struct glx_context_vtable indirect_context_vtable = {
324   indirect_destroy_context,
325   indirect_bind_context,
326   indirect_unbind_context,
327   indirect_wait_gl,
328   indirect_wait_x,
329   indirect_use_x_font,
330   indirect_bind_tex_image,
331   indirect_release_tex_image,
332};
333
334/**
335 * \todo Eliminate \c __glXInitVertexArrayState.  Replace it with a new
336 * function called \c __glXAllocateClientState that allocates the memory and
337 * does all the initialization (including the pixel pack / unpack).
338 */
339_X_HIDDEN struct glx_context *
340indirect_create_context(struct glx_screen *psc,
341			struct glx_config *mode,
342			struct glx_context *shareList, int renderType)
343{
344   struct glx_context *gc;
345   int bufSize;
346   CARD8 opcode;
347   __GLXattribute *state;
348
349   opcode = __glXSetupForCommand(psc->dpy);
350   if (!opcode) {
351      return NULL;
352   }
353
354   /* Allocate our context record */
355   gc = Xmalloc(sizeof *gc);
356   if (!gc) {
357      /* Out of memory */
358      return NULL;
359   }
360   memset(gc, 0, sizeof *gc);
361
362   glx_context_init(gc, psc, mode);
363   gc->isDirect = GL_FALSE;
364   gc->vtable = &indirect_context_vtable;
365   state = Xmalloc(sizeof(struct __GLXattributeRec));
366   if (state == NULL) {
367      /* Out of memory */
368      Xfree(gc);
369      return NULL;
370   }
371   gc->client_state_private = state;
372   memset(gc->client_state_private, 0, sizeof(struct __GLXattributeRec));
373   state->NoDrawArraysProtocol = (getenv("LIBGL_NO_DRAWARRAYS") != NULL);
374
375   /*
376    ** Create a temporary buffer to hold GLX rendering commands.  The size
377    ** of the buffer is selected so that the maximum number of GLX rendering
378    ** commands can fit in a single X packet and still have room in the X
379    ** packet for the GLXRenderReq header.
380    */
381
382   bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq;
383   gc->buf = (GLubyte *) Xmalloc(bufSize);
384   if (!gc->buf) {
385      Xfree(gc->client_state_private);
386      Xfree(gc);
387      return NULL;
388   }
389   gc->bufSize = bufSize;
390
391   /* Fill in the new context */
392   gc->renderMode = GL_RENDER;
393
394   state->storePack.alignment = 4;
395   state->storeUnpack.alignment = 4;
396
397   gc->attributes.stackPointer = &gc->attributes.stack[0];
398
399   /*
400    ** PERFORMANCE NOTE: A mode dependent fill image can speed things up.
401    ** Other code uses the fastImageUnpack bit, but it is never set
402    ** to GL_TRUE.
403    */
404   gc->fastImageUnpack = GL_FALSE;
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
438struct glx_screen_vtable indirect_screen_vtable = {
439   indirect_create_context
440};
441
442_X_HIDDEN struct glx_screen *
443indirect_create_screen(int screen, struct glx_display * priv)
444{
445   struct glx_screen *psc;
446
447   psc = Xmalloc(sizeof *psc);
448   if (psc == NULL)
449      return NULL;
450
451   memset(psc, 0, sizeof *psc);
452   glx_screen_init(psc, screen, priv);
453   psc->vtable = &indirect_screen_vtable;
454
455   return psc;
456}
457