13464ebd5Sriastradh/*
23464ebd5Sriastradh * Copyright © 2010 Intel Corporation
33464ebd5Sriastradh *
43464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
53464ebd5Sriastradh * copy of this software and associated documentation files (the "Soft-
63464ebd5Sriastradh * ware"), to deal in the Software without restriction, including without
73464ebd5Sriastradh * limitation the rights to use, copy, modify, merge, publish, distribute,
83464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the
93464ebd5Sriastradh * Software is furnished to do so, provided that the above copyright
103464ebd5Sriastradh * notice(s) and this permission notice appear in all copies of the Soft-
113464ebd5Sriastradh * ware and that both the above copyright notice(s) and this permission
123464ebd5Sriastradh * notice appear in supporting documentation.
133464ebd5Sriastradh *
143464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
153464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
163464ebd5Sriastradh * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
173464ebd5Sriastradh * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
183464ebd5Sriastradh * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
193464ebd5Sriastradh * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
203464ebd5Sriastradh * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
213464ebd5Sriastradh * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
223464ebd5Sriastradh * MANCE OF THIS SOFTWARE.
233464ebd5Sriastradh *
243464ebd5Sriastradh * Except as contained in this notice, the name of a copyright holder shall
253464ebd5Sriastradh * not be used in advertising or otherwise to promote the sale, use or
263464ebd5Sriastradh * other dealings in this Software without prior written authorization of
273464ebd5Sriastradh * the copyright holder.
283464ebd5Sriastradh *
293464ebd5Sriastradh * Authors:
303464ebd5Sriastradh *   Kristian Høgsberg (krh@bitplanet.net)
313464ebd5Sriastradh */
323464ebd5Sriastradh
3301e04c3fSmrg#include <stdbool.h>
3401e04c3fSmrg
353464ebd5Sriastradh#include "glapi.h"
363464ebd5Sriastradh#include "glxclient.h"
377ec681f3Smrg#include "indirect.h"
3801e04c3fSmrg#include "util/debug.h"
3901e04c3fSmrg
40af69d88dSmrg#ifndef GLX_USE_APPLEGL
41af69d88dSmrg
423464ebd5Sriastradhextern struct _glapi_table *__glXNewIndirectAPI(void);
433464ebd5Sriastradh
443464ebd5Sriastradh/*
453464ebd5Sriastradh** All indirect rendering contexts will share the same indirect dispatch table.
463464ebd5Sriastradh*/
473464ebd5Sriastradhstatic struct _glapi_table *IndirectAPI = NULL;
483464ebd5Sriastradh
497ec681f3Smrgstatic void
507ec681f3Smrg__glFreeAttributeState(struct glx_context * gc)
517ec681f3Smrg{
527ec681f3Smrg   __GLXattribute *sp, **spp;
537ec681f3Smrg
547ec681f3Smrg   for (spp = &gc->attributes.stack[0];
557ec681f3Smrg        spp < &gc->attributes.stack[__GL_CLIENT_ATTRIB_STACK_DEPTH]; spp++) {
567ec681f3Smrg      sp = *spp;
577ec681f3Smrg      if (sp) {
587ec681f3Smrg         free((char *) sp);
597ec681f3Smrg      }
607ec681f3Smrg      else {
617ec681f3Smrg         break;
627ec681f3Smrg      }
637ec681f3Smrg   }
647ec681f3Smrg}
657ec681f3Smrg
663464ebd5Sriastradhstatic void
673464ebd5Sriastradhindirect_destroy_context(struct glx_context *gc)
683464ebd5Sriastradh{
693464ebd5Sriastradh   __glXFreeVertexArrayState(gc);
703464ebd5Sriastradh
71af69d88dSmrg   free((char *) gc->vendor);
72af69d88dSmrg   free((char *) gc->renderer);
73af69d88dSmrg   free((char *) gc->version);
74af69d88dSmrg   free((char *) gc->extensions);
753464ebd5Sriastradh   __glFreeAttributeState(gc);
76af69d88dSmrg   free((char *) gc->buf);
77af69d88dSmrg   free((char *) gc->client_state_private);
78af69d88dSmrg   free((char *) gc);
793464ebd5Sriastradh}
803464ebd5Sriastradh
813464ebd5Sriastradhstatic Bool
8201e04c3fSmrgSendMakeCurrentRequest(Display * dpy, GLXContextID gc_id,
8301e04c3fSmrg                       GLXContextTag gc_tag, GLXDrawable draw,
8401e04c3fSmrg                       GLXDrawable read, GLXContextTag *out_tag)
853464ebd5Sriastradh{
86af69d88dSmrg   xGLXMakeCurrentReply reply;
873464ebd5Sriastradh   Bool ret;
8801e04c3fSmrg   int opcode = __glXSetupForCommand(dpy);
893464ebd5Sriastradh
903464ebd5Sriastradh   LockDisplay(dpy);
913464ebd5Sriastradh
923464ebd5Sriastradh   if (draw == read) {
933464ebd5Sriastradh      xGLXMakeCurrentReq *req;
943464ebd5Sriastradh
953464ebd5Sriastradh      GetReq(GLXMakeCurrent, req);
963464ebd5Sriastradh      req->reqType = opcode;
973464ebd5Sriastradh      req->glxCode = X_GLXMakeCurrent;
983464ebd5Sriastradh      req->drawable = draw;
993464ebd5Sriastradh      req->context = gc_id;
1003464ebd5Sriastradh      req->oldContextTag = gc_tag;
1013464ebd5Sriastradh   }
1023464ebd5Sriastradh   else {
1033464ebd5Sriastradh      struct glx_display *priv = __glXInitialize(dpy);
1043464ebd5Sriastradh
1053464ebd5Sriastradh      /* If the server can support the GLX 1.3 version, we should
1063464ebd5Sriastradh       * perfer that.  Not only that, some servers support GLX 1.3 but
1073464ebd5Sriastradh       * not the SGI extension.
1083464ebd5Sriastradh       */
1093464ebd5Sriastradh
1107ec681f3Smrg      if (priv->minorVersion >= 3) {
1113464ebd5Sriastradh         xGLXMakeContextCurrentReq *req;
1123464ebd5Sriastradh
1133464ebd5Sriastradh         GetReq(GLXMakeContextCurrent, req);
1143464ebd5Sriastradh         req->reqType = opcode;
1153464ebd5Sriastradh         req->glxCode = X_GLXMakeContextCurrent;
1163464ebd5Sriastradh         req->drawable = draw;
1173464ebd5Sriastradh         req->readdrawable = read;
1183464ebd5Sriastradh         req->context = gc_id;
1193464ebd5Sriastradh         req->oldContextTag = gc_tag;
1203464ebd5Sriastradh      }
1213464ebd5Sriastradh      else {
1223464ebd5Sriastradh         xGLXVendorPrivateWithReplyReq *vpreq;
1233464ebd5Sriastradh         xGLXMakeCurrentReadSGIReq *req;
1243464ebd5Sriastradh
1253464ebd5Sriastradh         GetReqExtra(GLXVendorPrivateWithReply,
1263464ebd5Sriastradh                     sz_xGLXMakeCurrentReadSGIReq -
1273464ebd5Sriastradh                     sz_xGLXVendorPrivateWithReplyReq, vpreq);
1283464ebd5Sriastradh         req = (xGLXMakeCurrentReadSGIReq *) vpreq;
1293464ebd5Sriastradh         req->reqType = opcode;
1303464ebd5Sriastradh         req->glxCode = X_GLXVendorPrivateWithReply;
1313464ebd5Sriastradh         req->vendorCode = X_GLXvop_MakeCurrentReadSGI;
1323464ebd5Sriastradh         req->drawable = draw;
1333464ebd5Sriastradh         req->readable = read;
1343464ebd5Sriastradh         req->context = gc_id;
1353464ebd5Sriastradh         req->oldContextTag = gc_tag;
1363464ebd5Sriastradh      }
1373464ebd5Sriastradh   }
1383464ebd5Sriastradh
139af69d88dSmrg   ret = _XReply(dpy, (xReply *) &reply, 0, False);
140af69d88dSmrg
141af69d88dSmrg   if (out_tag)
142af69d88dSmrg      *out_tag = reply.contextTag;
1433464ebd5Sriastradh
1443464ebd5Sriastradh   UnlockDisplay(dpy);
1453464ebd5Sriastradh   SyncHandle();
1463464ebd5Sriastradh
1473464ebd5Sriastradh   return ret;
1483464ebd5Sriastradh}
1493464ebd5Sriastradh
1503464ebd5Sriastradhstatic int
1513464ebd5Sriastradhindirect_bind_context(struct glx_context *gc, struct glx_context *old,
1523464ebd5Sriastradh		      GLXDrawable draw, GLXDrawable read)
1533464ebd5Sriastradh{
1543464ebd5Sriastradh   GLXContextTag tag;
1553464ebd5Sriastradh   Display *dpy = gc->psc->dpy;
156af69d88dSmrg   Bool sent;
1573464ebd5Sriastradh
1583464ebd5Sriastradh   if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) {
1593464ebd5Sriastradh      tag = old->currentContextTag;
1603464ebd5Sriastradh      old->currentContextTag = 0;
1613464ebd5Sriastradh   } else {
1623464ebd5Sriastradh      tag = 0;
1633464ebd5Sriastradh   }
1643464ebd5Sriastradh
16501e04c3fSmrg   sent = SendMakeCurrentRequest(dpy, gc->xid, tag, draw, read,
166af69d88dSmrg				 &gc->currentContextTag);
1673464ebd5Sriastradh
1687ec681f3Smrg   if (sent) {
1697ec681f3Smrg      if (!IndirectAPI)
1707ec681f3Smrg         IndirectAPI = __glXNewIndirectAPI();
1717ec681f3Smrg      _glapi_set_dispatch(IndirectAPI);
1727ec681f3Smrg
1737ec681f3Smrg      /* The indirect vertex array state must to be initialised after we
1747ec681f3Smrg       * have setup the context, as it needs to query server attributes.
1757ec681f3Smrg       *
1767ec681f3Smrg       * At the point this is called gc->currentDpy is not initialized
1777ec681f3Smrg       * nor is the thread's current context actually set. Hence the
1787ec681f3Smrg       * cleverness before the GetString calls.
1797ec681f3Smrg       */
1807ec681f3Smrg      __GLXattribute *state = gc->client_state_private;
1817ec681f3Smrg      if (state && state->array_state == NULL) {
1827ec681f3Smrg         gc->currentDpy = gc->psc->dpy;
1837ec681f3Smrg         __glXSetCurrentContext(gc);
1847ec681f3Smrg         __indirect_glGetString(GL_EXTENSIONS);
1857ec681f3Smrg         __indirect_glGetString(GL_VERSION);
1867ec681f3Smrg         __glXInitVertexArrayState(gc);
1877ec681f3Smrg      }
1887ec681f3Smrg   }
1893464ebd5Sriastradh
190af69d88dSmrg   return !sent;
1913464ebd5Sriastradh}
1923464ebd5Sriastradh
1933464ebd5Sriastradhstatic void
1943464ebd5Sriastradhindirect_unbind_context(struct glx_context *gc, struct glx_context *new)
1953464ebd5Sriastradh{
1963464ebd5Sriastradh   Display *dpy = gc->psc->dpy;
1973464ebd5Sriastradh
1983464ebd5Sriastradh   if (gc == new)
1993464ebd5Sriastradh      return;
2003464ebd5Sriastradh
20101e04c3fSmrg   /* We are either switching to no context, away from an indirect
2023464ebd5Sriastradh    * context to a direct context or from one dpy to another and have
2033464ebd5Sriastradh    * to send a request to the dpy to unbind the previous context.
2043464ebd5Sriastradh    */
2053464ebd5Sriastradh   if (!new || new->isDirect || new->psc->dpy != dpy) {
20601e04c3fSmrg      SendMakeCurrentRequest(dpy, None, gc->currentContextTag, None, None,
20701e04c3fSmrg                             NULL);
2083464ebd5Sriastradh      gc->currentContextTag = 0;
2093464ebd5Sriastradh   }
2103464ebd5Sriastradh}
2113464ebd5Sriastradh
2123464ebd5Sriastradhstatic void
2133464ebd5Sriastradhindirect_wait_gl(struct glx_context *gc)
2143464ebd5Sriastradh{
2153464ebd5Sriastradh   xGLXWaitGLReq *req;
2163464ebd5Sriastradh   Display *dpy = gc->currentDpy;
2173464ebd5Sriastradh
2183464ebd5Sriastradh   /* Flush any pending commands out */
2193464ebd5Sriastradh   __glXFlushRenderBuffer(gc, gc->pc);
2203464ebd5Sriastradh
2213464ebd5Sriastradh   /* Send the glXWaitGL request */
2223464ebd5Sriastradh   LockDisplay(dpy);
2233464ebd5Sriastradh   GetReq(GLXWaitGL, req);
2243464ebd5Sriastradh   req->reqType = gc->majorOpcode;
2253464ebd5Sriastradh   req->glxCode = X_GLXWaitGL;
2263464ebd5Sriastradh   req->contextTag = gc->currentContextTag;
2273464ebd5Sriastradh   UnlockDisplay(dpy);
2283464ebd5Sriastradh   SyncHandle();
2293464ebd5Sriastradh}
2303464ebd5Sriastradh
2313464ebd5Sriastradhstatic void
2323464ebd5Sriastradhindirect_wait_x(struct glx_context *gc)
2333464ebd5Sriastradh{
2343464ebd5Sriastradh   xGLXWaitXReq *req;
2353464ebd5Sriastradh   Display *dpy = gc->currentDpy;
2363464ebd5Sriastradh
2373464ebd5Sriastradh   /* Flush any pending commands out */
2383464ebd5Sriastradh   __glXFlushRenderBuffer(gc, gc->pc);
2393464ebd5Sriastradh
2403464ebd5Sriastradh   LockDisplay(dpy);
2413464ebd5Sriastradh   GetReq(GLXWaitX, req);
2423464ebd5Sriastradh   req->reqType = gc->majorOpcode;
2433464ebd5Sriastradh   req->glxCode = X_GLXWaitX;
2443464ebd5Sriastradh   req->contextTag = gc->currentContextTag;
2453464ebd5Sriastradh   UnlockDisplay(dpy);
2463464ebd5Sriastradh   SyncHandle();
2473464ebd5Sriastradh}
2483464ebd5Sriastradh
2493464ebd5Sriastradhstatic const struct glx_context_vtable indirect_context_vtable = {
250af69d88dSmrg   .destroy             = indirect_destroy_context,
251af69d88dSmrg   .bind                = indirect_bind_context,
252af69d88dSmrg   .unbind              = indirect_unbind_context,
253af69d88dSmrg   .wait_gl             = indirect_wait_gl,
254af69d88dSmrg   .wait_x              = indirect_wait_x,
2553464ebd5Sriastradh};
2563464ebd5Sriastradh
2577ec681f3Smrg_X_HIDDEN struct glx_context *
2587ec681f3Smrgindirect_create_context(struct glx_screen *psc,
2597ec681f3Smrg			struct glx_config *mode,
2607ec681f3Smrg			struct glx_context *shareList, int renderType)
2617ec681f3Smrg{
2627ec681f3Smrg   unsigned error = 0;
2637ec681f3Smrg   const uint32_t attribs[] = { GLX_RENDER_TYPE, renderType };
2647ec681f3Smrg
2657ec681f3Smrg   return indirect_create_context_attribs(psc, mode, shareList,
2667ec681f3Smrg                                          1, attribs, &error);
2677ec681f3Smrg}
2687ec681f3Smrg
2693464ebd5Sriastradh/**
2703464ebd5Sriastradh * \todo Eliminate \c __glXInitVertexArrayState.  Replace it with a new
2713464ebd5Sriastradh * function called \c __glXAllocateClientState that allocates the memory and
2723464ebd5Sriastradh * does all the initialization (including the pixel pack / unpack).
2733464ebd5Sriastradh */
2743464ebd5Sriastradh_X_HIDDEN struct glx_context *
2757ec681f3Smrgindirect_create_context_attribs(struct glx_screen *psc,
2767ec681f3Smrg				struct glx_config *mode,
2777ec681f3Smrg				struct glx_context *shareList,
2787ec681f3Smrg				unsigned num_attribs,
2797ec681f3Smrg				const uint32_t *attribs,
2807ec681f3Smrg				unsigned *error)
2813464ebd5Sriastradh{
2823464ebd5Sriastradh   struct glx_context *gc;
2833464ebd5Sriastradh   int bufSize;
2843464ebd5Sriastradh   CARD8 opcode;
2853464ebd5Sriastradh   __GLXattribute *state;
2867ec681f3Smrg   int i, renderType = GLX_RGBA_TYPE;
2877ec681f3Smrg   uint32_t mask = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
2887ec681f3Smrg   uint32_t major = 1;
2897ec681f3Smrg   uint32_t minor = 0;
2903464ebd5Sriastradh
2913464ebd5Sriastradh   opcode = __glXSetupForCommand(psc->dpy);
2923464ebd5Sriastradh   if (!opcode) {
2933464ebd5Sriastradh      return NULL;
2943464ebd5Sriastradh   }
2953464ebd5Sriastradh
2967ec681f3Smrg   for (i = 0; i < num_attribs; i++) {
2977ec681f3Smrg      uint32_t attr = attribs[i*2], val = attribs[i*2 + 1];
2987ec681f3Smrg
2997ec681f3Smrg      if (attr == GLX_RENDER_TYPE)
3007ec681f3Smrg         renderType = val;
3017ec681f3Smrg      if (attr == GLX_CONTEXT_PROFILE_MASK_ARB)
3027ec681f3Smrg         mask = val;
3037ec681f3Smrg      if (attr == GLX_CONTEXT_MAJOR_VERSION_ARB)
3047ec681f3Smrg         major = val;
3057ec681f3Smrg      if (attr == GLX_CONTEXT_MINOR_VERSION_ARB)
3067ec681f3Smrg         minor = val;
3077ec681f3Smrg   }
3087ec681f3Smrg
3097ec681f3Smrg   /* We have no indirect support for core or ES contexts, and our compat
3107ec681f3Smrg    * context support is limited to GL 1.4.
3117ec681f3Smrg    */
3127ec681f3Smrg   if (mask != GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ||
3137ec681f3Smrg       major != 1 ||
3147ec681f3Smrg       minor > 4) {
3157ec681f3Smrg      return NULL;
3167ec681f3Smrg   }
3177ec681f3Smrg
3187ec681f3Smrg   /* We can't share with a direct context */
3197ec681f3Smrg   if (shareList && shareList->isDirect)
3207ec681f3Smrg      return NULL;
3217ec681f3Smrg
3223464ebd5Sriastradh   /* Allocate our context record */
323af69d88dSmrg   gc = calloc(1, sizeof *gc);
3243464ebd5Sriastradh   if (!gc) {
3253464ebd5Sriastradh      /* Out of memory */
3263464ebd5Sriastradh      return NULL;
3273464ebd5Sriastradh   }
3283464ebd5Sriastradh
3293464ebd5Sriastradh   glx_context_init(gc, psc, mode);
3303464ebd5Sriastradh   gc->isDirect = GL_FALSE;
3313464ebd5Sriastradh   gc->vtable = &indirect_context_vtable;
332af69d88dSmrg   state = calloc(1, sizeof(struct __GLXattributeRec));
333af69d88dSmrg   gc->renderType = renderType;
334af69d88dSmrg
3353464ebd5Sriastradh   if (state == NULL) {
3363464ebd5Sriastradh      /* Out of memory */
337af69d88dSmrg      free(gc);
3383464ebd5Sriastradh      return NULL;
3393464ebd5Sriastradh   }
3403464ebd5Sriastradh   gc->client_state_private = state;
34101e04c3fSmrg   state->NoDrawArraysProtocol = env_var_as_boolean("LIBGL_NO_DRAWARRAYS", false);
3423464ebd5Sriastradh
3433464ebd5Sriastradh   /*
3443464ebd5Sriastradh    ** Create a temporary buffer to hold GLX rendering commands.  The size
3453464ebd5Sriastradh    ** of the buffer is selected so that the maximum number of GLX rendering
3463464ebd5Sriastradh    ** commands can fit in a single X packet and still have room in the X
3473464ebd5Sriastradh    ** packet for the GLXRenderReq header.
3483464ebd5Sriastradh    */
3493464ebd5Sriastradh
3503464ebd5Sriastradh   bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq;
351af69d88dSmrg   gc->buf = malloc(bufSize);
3523464ebd5Sriastradh   if (!gc->buf) {
353af69d88dSmrg      free(gc->client_state_private);
354af69d88dSmrg      free(gc);
3553464ebd5Sriastradh      return NULL;
3563464ebd5Sriastradh   }
3573464ebd5Sriastradh   gc->bufSize = bufSize;
3583464ebd5Sriastradh
3593464ebd5Sriastradh   /* Fill in the new context */
3603464ebd5Sriastradh   gc->renderMode = GL_RENDER;
3613464ebd5Sriastradh
3623464ebd5Sriastradh   state->storePack.alignment = 4;
3633464ebd5Sriastradh   state->storeUnpack.alignment = 4;
3643464ebd5Sriastradh
3653464ebd5Sriastradh   gc->attributes.stackPointer = &gc->attributes.stack[0];
3663464ebd5Sriastradh
3673464ebd5Sriastradh   gc->pc = gc->buf;
3683464ebd5Sriastradh   gc->bufEnd = gc->buf + bufSize;
3693464ebd5Sriastradh   gc->isDirect = GL_FALSE;
3703464ebd5Sriastradh   if (__glXDebug) {
3713464ebd5Sriastradh      /*
3723464ebd5Sriastradh       ** Set limit register so that there will be one command per packet
3733464ebd5Sriastradh       */
3743464ebd5Sriastradh      gc->limit = gc->buf;
3753464ebd5Sriastradh   }
3763464ebd5Sriastradh   else {
3773464ebd5Sriastradh      gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
3783464ebd5Sriastradh   }
3793464ebd5Sriastradh   gc->majorOpcode = opcode;
3803464ebd5Sriastradh
3813464ebd5Sriastradh   /*
3823464ebd5Sriastradh    ** Constrain the maximum drawing command size allowed to be
3837ec681f3Smrg    ** transferred using the X_GLXRender protocol request.  First
3847ec681f3Smrg    ** constrain by a software limit, then constrain by the protocol
3853464ebd5Sriastradh    ** limit.
3863464ebd5Sriastradh    */
3877ec681f3Smrg   gc->maxSmallRenderCommandSize = MIN3(bufSize, __GLX_RENDER_CMD_SIZE_LIMIT,
3887ec681f3Smrg                                        __GLX_MAX_RENDER_CMD_SIZE);
389af69d88dSmrg
390af69d88dSmrg
3917ec681f3Smrg   return gc;
392af69d88dSmrg}
393af69d88dSmrg
394af69d88dSmrgstatic const struct glx_screen_vtable indirect_screen_vtable = {
395af69d88dSmrg   .create_context         = indirect_create_context,
396af69d88dSmrg   .create_context_attribs = indirect_create_context_attribs,
397af69d88dSmrg   .query_renderer_integer = NULL,
398af69d88dSmrg   .query_renderer_string  = NULL,
3993464ebd5Sriastradh};
4003464ebd5Sriastradh
4013464ebd5Sriastradh_X_HIDDEN struct glx_screen *
4023464ebd5Sriastradhindirect_create_screen(int screen, struct glx_display * priv)
4033464ebd5Sriastradh{
4043464ebd5Sriastradh   struct glx_screen *psc;
4053464ebd5Sriastradh
406af69d88dSmrg   psc = calloc(1, sizeof *psc);
4073464ebd5Sriastradh   if (psc == NULL)
4083464ebd5Sriastradh      return NULL;
4093464ebd5Sriastradh
4103464ebd5Sriastradh   glx_screen_init(psc, screen, priv);
4113464ebd5Sriastradh   psc->vtable = &indirect_screen_vtable;
4123464ebd5Sriastradh
4133464ebd5Sriastradh   return psc;
4143464ebd5Sriastradh}
415af69d88dSmrg
416af69d88dSmrg#endif
417