xref: /aosp_15_r20/external/mesa3d/src/glx/indirect_glx.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 ([email protected])
31  */
32 
33 #include <stdbool.h>
34 
35 #include "glapi.h"
36 #include "glxclient.h"
37 #include "indirect.h"
38 #include "util/u_debug.h"
39 
40 #if !defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE)
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       xGLXMakeContextCurrentReq *req;
104 
105       GetReq(GLXMakeContextCurrent, req);
106       req->reqType = opcode;
107       req->glxCode = X_GLXMakeContextCurrent;
108       req->drawable = draw;
109       req->readdrawable = read;
110       req->context = gc_id;
111       req->oldContextTag = gc_tag;
112    }
113 
114    ret = _XReply(dpy, (xReply *) &reply, 0, False);
115 
116    if (out_tag)
117       *out_tag = reply.contextTag;
118 
119    UnlockDisplay(dpy);
120    SyncHandle();
121 
122    return ret;
123 }
124 
125 static int
indirect_bind_context(struct glx_context * gc,GLXDrawable draw,GLXDrawable read)126 indirect_bind_context(struct glx_context *gc,
127             GLXDrawable draw, GLXDrawable read)
128 {
129    Display *dpy = gc->psc->dpy;
130    Bool sent;
131 
132    sent = SendMakeCurrentRequest(dpy, gc->xid, 0, draw, read,
133              &gc->currentContextTag);
134 
135    if (sent) {
136       if (!IndirectAPI)
137          IndirectAPI = __glXNewIndirectAPI();
138       _glapi_set_dispatch(IndirectAPI);
139 
140       /* The indirect vertex array state must to be initialised after we
141        * have setup the context, as it needs to query server attributes.
142        *
143        * At the point this is called gc->currentDpy is not initialized
144        * nor is the thread's current context actually set. Hence the
145        * cleverness before the GetString calls.
146        */
147       __GLXattribute *state = gc->client_state_private;
148       if (state && state->array_state == NULL) {
149          gc->currentDpy = gc->psc->dpy;
150          __glXSetCurrentContext(gc);
151          __indirect_glGetString(GL_EXTENSIONS);
152          __indirect_glGetString(GL_VERSION);
153          __glXInitVertexArrayState(gc);
154       }
155    }
156 
157    return !sent;
158 }
159 
160 static void
indirect_unbind_context(struct glx_context * gc)161 indirect_unbind_context(struct glx_context *gc)
162 {
163    Display *dpy = gc->psc->dpy;
164 
165    SendMakeCurrentRequest(dpy, None, gc->currentContextTag, None, None, NULL);
166    gc->currentContextTag = 0;
167 }
168 
169 static void
indirect_wait_gl(struct glx_context * gc)170 indirect_wait_gl(struct glx_context *gc)
171 {
172    xGLXWaitGLReq *req;
173    Display *dpy = gc->currentDpy;
174 
175    /* Flush any pending commands out */
176    __glXFlushRenderBuffer(gc, gc->pc);
177 
178    /* Send the glXWaitGL request */
179    LockDisplay(dpy);
180    GetReq(GLXWaitGL, req);
181    req->reqType = gc->majorOpcode;
182    req->glxCode = X_GLXWaitGL;
183    req->contextTag = gc->currentContextTag;
184    UnlockDisplay(dpy);
185    SyncHandle();
186 }
187 
188 static void
indirect_wait_x(struct glx_context * gc)189 indirect_wait_x(struct glx_context *gc)
190 {
191    xGLXWaitXReq *req;
192    Display *dpy = gc->currentDpy;
193 
194    /* Flush any pending commands out */
195    __glXFlushRenderBuffer(gc, gc->pc);
196 
197    LockDisplay(dpy);
198    GetReq(GLXWaitX, req);
199    req->reqType = gc->majorOpcode;
200    req->glxCode = X_GLXWaitX;
201    req->contextTag = gc->currentContextTag;
202    UnlockDisplay(dpy);
203    SyncHandle();
204 }
205 
206 static const struct glx_context_vtable indirect_context_vtable = {
207    .destroy             = indirect_destroy_context,
208    .bind                = indirect_bind_context,
209    .unbind              = indirect_unbind_context,
210    .wait_gl             = indirect_wait_gl,
211    .wait_x              = indirect_wait_x,
212 };
213 
214 _X_HIDDEN struct glx_context *
indirect_create_context(struct glx_screen * psc,struct glx_config * mode,struct glx_context * shareList,int renderType)215 indirect_create_context(struct glx_screen *psc,
216          struct glx_config *mode,
217          struct glx_context *shareList, int renderType)
218 {
219    unsigned error = 0;
220    const uint32_t attribs[] = { GLX_RENDER_TYPE, renderType };
221 
222    return indirect_create_context_attribs(psc, mode, shareList,
223                                           1, attribs, &error);
224 }
225 
226 /**
227  * \todo Eliminate \c __glXInitVertexArrayState.  Replace it with a new
228  * function called \c __glXAllocateClientState that allocates the memory and
229  * does all the initialization (including the pixel pack / unpack).
230  */
231 _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)232 indirect_create_context_attribs(struct glx_screen *psc,
233             struct glx_config *mode,
234             struct glx_context *shareList,
235             unsigned num_attribs,
236             const uint32_t *attribs,
237             unsigned *error)
238 {
239    struct glx_context *gc;
240    int bufSize;
241    CARD8 opcode;
242    __GLXattribute *state;
243    int i, renderType = GLX_RGBA_TYPE;
244    uint32_t mask = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
245    uint32_t major = 1;
246    uint32_t minor = 0;
247 
248    opcode = __glXSetupForCommand(psc->dpy);
249    if (!opcode) {
250       *error = BadImplementation;
251       return NULL;
252    }
253 
254    for (i = 0; i < num_attribs; i++) {
255       uint32_t attr = attribs[i*2], val = attribs[i*2 + 1];
256 
257       if (attr == GLX_RENDER_TYPE)
258          renderType = val;
259       if (attr == GLX_CONTEXT_PROFILE_MASK_ARB)
260          mask = val;
261       if (attr == GLX_CONTEXT_MAJOR_VERSION_ARB)
262          major = val;
263       if (attr == GLX_CONTEXT_MINOR_VERSION_ARB)
264          minor = val;
265    }
266 
267    /* We have no indirect support for core or ES contexts, and our compat
268     * context support is limited to GL 1.4.
269     */
270    if (mask != GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ||
271        major != 1 ||
272        minor > 4) {
273       *error = GLXBadFBConfig;
274       return NULL;
275    }
276 
277    /* We can't share with a direct context */
278    if (shareList && shareList->isDirect)
279       return NULL;
280 
281    /* Allocate our context record */
282    gc = calloc(1, sizeof *gc);
283    if (!gc) {
284       *error = BadAlloc;
285       /* Out of memory */
286       return NULL;
287    }
288 
289    glx_context_init(gc, psc, mode);
290    gc->isDirect = GL_FALSE;
291    gc->vtable = &indirect_context_vtable;
292    state = calloc(1, sizeof(struct __GLXattributeRec));
293    gc->renderType = renderType;
294 
295    if (state == NULL) {
296       /* Out of memory */
297       *error = BadAlloc;
298       free(gc);
299       return NULL;
300    }
301    gc->client_state_private = state;
302    state->NoDrawArraysProtocol = debug_get_bool_option("LIBGL_NO_DRAWARRAYS", false);
303 
304    /*
305     ** Create a temporary buffer to hold GLX rendering commands.  The size
306     ** of the buffer is selected so that the maximum number of GLX rendering
307     ** commands can fit in a single X packet and still have room in the X
308     ** packet for the GLXRenderReq header.
309     */
310 
311    bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq;
312    gc->buf = malloc(bufSize);
313    if (!gc->buf) {
314       *error = BadAlloc;
315       free(gc->client_state_private);
316       free(gc);
317       return NULL;
318    }
319    gc->bufSize = bufSize;
320 
321    /* Fill in the new context */
322    gc->renderMode = GL_RENDER;
323 
324    state->storePack.alignment = 4;
325    state->storeUnpack.alignment = 4;
326 
327    gc->attributes.stackPointer = &gc->attributes.stack[0];
328 
329    gc->pc = gc->buf;
330    gc->bufEnd = gc->buf + bufSize;
331    gc->isDirect = GL_FALSE;
332    if (__glXDebug) {
333       /*
334        ** Set limit register so that there will be one command per packet
335        */
336       gc->limit = gc->buf;
337    }
338    else {
339       gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
340    }
341    gc->majorOpcode = opcode;
342 
343    /*
344     ** Constrain the maximum drawing command size allowed to be
345     ** transferred using the X_GLXRender protocol request.  First
346     ** constrain by a software limit, then constrain by the protocol
347     ** limit.
348     */
349    gc->maxSmallRenderCommandSize = MIN3(bufSize, __GLX_RENDER_CMD_SIZE_LIMIT,
350                                         __GLX_MAX_RENDER_CMD_SIZE);
351 
352 
353    return gc;
354 }
355 
356 static const struct glx_screen_vtable indirect_screen_vtable = {
357    .create_context         = indirect_create_context,
358    .create_context_attribs = indirect_create_context_attribs,
359    .query_renderer_integer = NULL,
360    .query_renderer_string  = NULL,
361 };
362 
363 _X_HIDDEN struct glx_screen *
indirect_create_screen(int screen,struct glx_display * priv)364 indirect_create_screen(int screen, struct glx_display * priv)
365 {
366    struct glx_screen *psc;
367 
368    psc = calloc(1, sizeof *psc);
369    if (psc == NULL)
370       return NULL;
371 
372    glx_screen_init(psc, screen, priv);
373    psc->vtable = &indirect_screen_vtable;
374 
375    return psc;
376 }
377 
378 #endif
379