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
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 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
150 static int
indirect_bind_context(struct glx_context * gc,struct glx_context * old,GLXDrawable draw,GLXDrawable read)151 indirect_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
193 static void
indirect_unbind_context(struct glx_context * gc,struct glx_context * new)194 indirect_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
212 static void
indirect_wait_gl(struct glx_context * gc)213 indirect_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
231 static void
indirect_wait_x(struct glx_context * gc)232 indirect_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
249 static 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 *
indirect_create_context(struct glx_screen * psc,struct glx_config * mode,struct glx_context * shareList,int renderType)258 indirect_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 *
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)275 indirect_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
394 static 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 *
indirect_create_screen(int screen,struct glx_display * priv)402 indirect_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