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