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
indirect_destroy_context(struct glx_context * gc)50 indirect_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
64 static Bool
SendMakeCurrentRequest(Display * dpy,GLXContextID gc_id,GLXContextTag gc_tag,GLXDrawable draw,GLXDrawable read,GLXContextTag * out_tag)65 SendMakeCurrentRequest(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
133 static int
indirect_bind_context(struct glx_context * gc,struct glx_context * old,GLXDrawable draw,GLXDrawable read)134 indirect_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 (sent) {
152 if (!IndirectAPI)
153 IndirectAPI = __glXNewIndirectAPI();
154 _glapi_set_dispatch(IndirectAPI);
155
156 /* The indirect vertex array state must to be initialised after we
157 * have setup the context, as it needs to query server attributes.
158 *
159 * At the point this is called gc->currentDpy is not initialized
160 * nor is the thread's current context actually set. Hence the
161 * cleverness before the GetString calls.
162 */
163 __GLXattribute *state = gc->client_state_private;
164 if (state && state->array_state == NULL) {
165 gc->currentDpy = gc->psc->dpy;
166 __glXSetCurrentContext(gc);
167 __indirect_glGetString(GL_EXTENSIONS);
168 __indirect_glGetString(GL_VERSION);
169 __glXInitVertexArrayState(gc);
170 }
171 }
172
173 return !sent;
174 }
175
176 static void
indirect_unbind_context(struct glx_context * gc,struct glx_context * new)177 indirect_unbind_context(struct glx_context *gc, struct glx_context *new)
178 {
179 Display *dpy = gc->psc->dpy;
180
181 if (gc == new)
182 return;
183
184 /* We are either switching to no context, away from an indirect
185 * context to a direct context or from one dpy to another and have
186 * to send a request to the dpy to unbind the previous context.
187 */
188 if (!new || new->isDirect || new->psc->dpy != dpy) {
189 SendMakeCurrentRequest(dpy, None, gc->currentContextTag, None, None,
190 NULL);
191 gc->currentContextTag = 0;
192 }
193 }
194
195 static void
indirect_wait_gl(struct glx_context * gc)196 indirect_wait_gl(struct glx_context *gc)
197 {
198 xGLXWaitGLReq *req;
199 Display *dpy = gc->currentDpy;
200
201 /* Flush any pending commands out */
202 __glXFlushRenderBuffer(gc, gc->pc);
203
204 /* Send the glXWaitGL request */
205 LockDisplay(dpy);
206 GetReq(GLXWaitGL, req);
207 req->reqType = gc->majorOpcode;
208 req->glxCode = X_GLXWaitGL;
209 req->contextTag = gc->currentContextTag;
210 UnlockDisplay(dpy);
211 SyncHandle();
212 }
213
214 static void
indirect_wait_x(struct glx_context * gc)215 indirect_wait_x(struct glx_context *gc)
216 {
217 xGLXWaitXReq *req;
218 Display *dpy = gc->currentDpy;
219
220 /* Flush any pending commands out */
221 __glXFlushRenderBuffer(gc, gc->pc);
222
223 LockDisplay(dpy);
224 GetReq(GLXWaitX, req);
225 req->reqType = gc->majorOpcode;
226 req->glxCode = X_GLXWaitX;
227 req->contextTag = gc->currentContextTag;
228 UnlockDisplay(dpy);
229 SyncHandle();
230 }
231
232 static void
indirect_use_x_font(struct glx_context * gc,Font font,int first,int count,int listBase)233 indirect_use_x_font(struct glx_context *gc,
234 Font font, int first, int count, int listBase)
235 {
236 xGLXUseXFontReq *req;
237 Display *dpy = gc->currentDpy;
238
239 /* Flush any pending commands out */
240 __glXFlushRenderBuffer(gc, gc->pc);
241
242 /* Send the glXUseFont request */
243 LockDisplay(dpy);
244 GetReq(GLXUseXFont, req);
245 req->reqType = gc->majorOpcode;
246 req->glxCode = X_GLXUseXFont;
247 req->contextTag = gc->currentContextTag;
248 req->font = font;
249 req->first = first;
250 req->count = count;
251 req->listBase = listBase;
252 UnlockDisplay(dpy);
253 SyncHandle();
254 }
255
256 static void
indirect_bind_tex_image(Display * dpy,GLXDrawable drawable,int buffer,const int * attrib_list)257 indirect_bind_tex_image(Display * dpy,
258 GLXDrawable drawable,
259 int buffer, const int *attrib_list)
260 {
261 xGLXVendorPrivateReq *req;
262 struct glx_context *gc = __glXGetCurrentContext();
263 CARD32 *drawable_ptr;
264 INT32 *buffer_ptr;
265 CARD32 *num_attrib_ptr;
266 CARD32 *attrib_ptr;
267 CARD8 opcode;
268 unsigned int i;
269
270 i = 0;
271 if (attrib_list) {
272 while (attrib_list[i * 2] != None)
273 i++;
274 }
275
276 opcode = __glXSetupForCommand(dpy);
277 if (!opcode)
278 return;
279
280 LockDisplay(dpy);
281 GetReqExtra(GLXVendorPrivate, 12 + 8 * i, req);
282 req->reqType = opcode;
283 req->glxCode = X_GLXVendorPrivate;
284 req->vendorCode = X_GLXvop_BindTexImageEXT;
285 req->contextTag = gc->currentContextTag;
286
287 drawable_ptr = (CARD32 *) (req + 1);
288 buffer_ptr = (INT32 *) (drawable_ptr + 1);
289 num_attrib_ptr = (CARD32 *) (buffer_ptr + 1);
290 attrib_ptr = (CARD32 *) (num_attrib_ptr + 1);
291
292 *drawable_ptr = drawable;
293 *buffer_ptr = buffer;
294 *num_attrib_ptr = (CARD32) i;
295
296 i = 0;
297 if (attrib_list) {
298 while (attrib_list[i * 2] != None) {
299 *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 0];
300 *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 1];
301 i++;
302 }
303 }
304
305 UnlockDisplay(dpy);
306 SyncHandle();
307 }
308
309 static void
indirect_release_tex_image(Display * dpy,GLXDrawable drawable,int buffer)310 indirect_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
311 {
312 xGLXVendorPrivateReq *req;
313 struct glx_context *gc = __glXGetCurrentContext();
314 CARD32 *drawable_ptr;
315 INT32 *buffer_ptr;
316 CARD8 opcode;
317
318 opcode = __glXSetupForCommand(dpy);
319 if (!opcode)
320 return;
321
322 LockDisplay(dpy);
323 GetReqExtra(GLXVendorPrivate, sizeof(CARD32) + sizeof(INT32), req);
324 req->reqType = opcode;
325 req->glxCode = X_GLXVendorPrivate;
326 req->vendorCode = X_GLXvop_ReleaseTexImageEXT;
327 req->contextTag = gc->currentContextTag;
328
329 drawable_ptr = (CARD32 *) (req + 1);
330 buffer_ptr = (INT32 *) (drawable_ptr + 1);
331
332 *drawable_ptr = drawable;
333 *buffer_ptr = buffer;
334
335 UnlockDisplay(dpy);
336 SyncHandle();
337 }
338
339 static const struct glx_context_vtable indirect_context_vtable = {
340 .destroy = indirect_destroy_context,
341 .bind = indirect_bind_context,
342 .unbind = indirect_unbind_context,
343 .wait_gl = indirect_wait_gl,
344 .wait_x = indirect_wait_x,
345 .use_x_font = indirect_use_x_font,
346 .bind_tex_image = indirect_bind_tex_image,
347 .release_tex_image = indirect_release_tex_image,
348 .get_proc_address = NULL,
349 };
350
351 /**
352 * \todo Eliminate \c __glXInitVertexArrayState. Replace it with a new
353 * function called \c __glXAllocateClientState that allocates the memory and
354 * does all the initialization (including the pixel pack / unpack).
355 *
356 * \note
357 * This function is \b not the place to validate the context creation
358 * parameters. It is just the allocator for the \c glx_context.
359 */
360 _X_HIDDEN struct glx_context *
indirect_create_context(struct glx_screen * psc,struct glx_config * mode,struct glx_context * shareList,int renderType)361 indirect_create_context(struct glx_screen *psc,
362 struct glx_config *mode,
363 struct glx_context *shareList, int renderType)
364 {
365 struct glx_context *gc;
366 int bufSize;
367 CARD8 opcode;
368 __GLXattribute *state;
369
370 opcode = __glXSetupForCommand(psc->dpy);
371 if (!opcode) {
372 return NULL;
373 }
374
375 /* Allocate our context record */
376 gc = calloc(1, sizeof *gc);
377 if (!gc) {
378 /* Out of memory */
379 return NULL;
380 }
381
382 glx_context_init(gc, psc, mode);
383 gc->isDirect = GL_FALSE;
384 gc->vtable = &indirect_context_vtable;
385 state = calloc(1, sizeof(struct __GLXattributeRec));
386 gc->renderType = renderType;
387
388 if (state == NULL) {
389 /* Out of memory */
390 free(gc);
391 return NULL;
392 }
393 gc->client_state_private = state;
394 state->NoDrawArraysProtocol = env_var_as_boolean("LIBGL_NO_DRAWARRAYS", false);
395
396 /*
397 ** Create a temporary buffer to hold GLX rendering commands. The size
398 ** of the buffer is selected so that the maximum number of GLX rendering
399 ** commands can fit in a single X packet and still have room in the X
400 ** packet for the GLXRenderReq header.
401 */
402
403 bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq;
404 gc->buf = malloc(bufSize);
405 if (!gc->buf) {
406 free(gc->client_state_private);
407 free(gc);
408 return NULL;
409 }
410 gc->bufSize = bufSize;
411
412 /* Fill in the new context */
413 gc->renderMode = GL_RENDER;
414
415 state->storePack.alignment = 4;
416 state->storeUnpack.alignment = 4;
417
418 gc->attributes.stackPointer = &gc->attributes.stack[0];
419
420 gc->pc = gc->buf;
421 gc->bufEnd = gc->buf + bufSize;
422 gc->isDirect = GL_FALSE;
423 if (__glXDebug) {
424 /*
425 ** Set limit register so that there will be one command per packet
426 */
427 gc->limit = gc->buf;
428 }
429 else {
430 gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
431 }
432 gc->majorOpcode = opcode;
433
434 /*
435 ** Constrain the maximum drawing command size allowed to be
436 ** transfered using the X_GLXRender protocol request. First
437 ** constrain by a software limit, then constrain by the protocl
438 ** limit.
439 */
440 if (bufSize > __GLX_RENDER_CMD_SIZE_LIMIT) {
441 bufSize = __GLX_RENDER_CMD_SIZE_LIMIT;
442 }
443 if (bufSize > __GLX_MAX_RENDER_CMD_SIZE) {
444 bufSize = __GLX_MAX_RENDER_CMD_SIZE;
445 }
446 gc->maxSmallRenderCommandSize = bufSize;
447
448
449 return gc;
450 }
451
452 _X_HIDDEN struct glx_context *
indirect_create_context_attribs(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,unsigned num_attribs,const uint32_t * attribs,unsigned * error)453 indirect_create_context_attribs(struct glx_screen *base,
454 struct glx_config *config_base,
455 struct glx_context *shareList,
456 unsigned num_attribs,
457 const uint32_t *attribs,
458 unsigned *error)
459 {
460 int renderType = GLX_RGBA_TYPE;
461 unsigned i;
462
463 /* The error parameter is only used on the server so that correct GLX
464 * protocol errors can be generated. On the client, it can be ignored.
465 */
466 (void) error;
467
468 /* All of the attribute validation for indirect contexts is handled on the
469 * server, so there's not much to do here. Still, we need to parse the
470 * attributes to correctly set renderType.
471 */
472 for (i = 0; i < num_attribs; i++) {
473 if (attribs[i * 2] == GLX_RENDER_TYPE)
474 renderType = attribs[i * 2 + 1];
475 }
476
477 return indirect_create_context(base, config_base, shareList, renderType);
478 }
479
480 static const struct glx_screen_vtable indirect_screen_vtable = {
481 .create_context = indirect_create_context,
482 .create_context_attribs = indirect_create_context_attribs,
483 .query_renderer_integer = NULL,
484 .query_renderer_string = NULL,
485 };
486
487 _X_HIDDEN struct glx_screen *
indirect_create_screen(int screen,struct glx_display * priv)488 indirect_create_screen(int screen, struct glx_display * priv)
489 {
490 struct glx_screen *psc;
491
492 psc = calloc(1, sizeof *psc);
493 if (psc == NULL)
494 return NULL;
495
496 glx_screen_init(psc, screen, priv);
497 psc->vtable = &indirect_screen_vtable;
498
499 return psc;
500 }
501
502 #endif
503