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
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
50indirect_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
64static Bool
65SendMakeCurrentRequest(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
133static int
134indirect_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
158static void
159indirect_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
177static void
178indirect_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
196static void
197indirect_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
214static void
215indirect_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
238static void
239indirect_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
291static void
292indirect_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
321static 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 *
343indirect_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 *
439indirect_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
466static 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 *
474indirect_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