single2.c revision 6747b715
1/*
2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice including the dates of first publication and
13 * either this permission notice or a reference to
14 * http://oss.sgi.com/projects/FreeB/
15 * shall be included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Except as contained in this notice, the name of Silicon Graphics, Inc.
26 * shall not be used in advertising or otherwise to promote the sale, use or
27 * other dealings in this Software without prior written authorization from
28 * Silicon Graphics, Inc.
29 */
30
31#ifdef HAVE_DIX_CONFIG_H
32#include <dix-config.h>
33#endif
34
35#include <string.h>
36#include <stdio.h>
37#include <stdlib.h>
38
39#include "glxserver.h"
40#include "glxutil.h"
41#include "glxext.h"
42#include "indirect_dispatch.h"
43#include "unpack.h"
44#include "glapitable.h"
45#include "glapi.h"
46#include "glthread.h"
47#include "dispatch.h"
48
49int __glXDisp_FeedbackBuffer(__GLXclientState *cl, GLbyte *pc)
50{
51    GLsizei size;
52    GLenum type;
53    __GLXcontext *cx;
54    int error;
55
56    cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
57    if (!cx) {
58	return error;
59    }
60
61    pc += __GLX_SINGLE_HDR_SIZE;
62    size = *(GLsizei *)(pc+0);
63    type = *(GLenum *)(pc+4);
64    if (cx->feedbackBufSize < size) {
65	cx->feedbackBuf = (GLfloat *) realloc(cx->feedbackBuf,
66						   (size_t)size
67						   * __GLX_SIZE_FLOAT32);
68	if (!cx->feedbackBuf) {
69	    cl->client->errorValue = size;
70	    return BadAlloc;
71	}
72	cx->feedbackBufSize = size;
73    }
74    CALL_FeedbackBuffer( GET_DISPATCH(), (size, type, cx->feedbackBuf) );
75    __GLX_NOTE_UNFLUSHED_CMDS(cx);
76    return Success;
77}
78
79int __glXDisp_SelectBuffer(__GLXclientState *cl, GLbyte *pc)
80{
81    __GLXcontext *cx;
82    GLsizei size;
83    int error;
84
85    cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
86    if (!cx) {
87	return error;
88    }
89
90    pc += __GLX_SINGLE_HDR_SIZE;
91    size = *(GLsizei *)(pc+0);
92    if (cx->selectBufSize < size) {
93	cx->selectBuf = (GLuint *) realloc(cx->selectBuf,
94						(size_t) size
95						* __GLX_SIZE_CARD32);
96	if (!cx->selectBuf) {
97	    cl->client->errorValue = size;
98	    return BadAlloc;
99	}
100	cx->selectBufSize = size;
101    }
102    CALL_SelectBuffer( GET_DISPATCH(), (size, cx->selectBuf) );
103    __GLX_NOTE_UNFLUSHED_CMDS(cx);
104    return Success;
105}
106
107int __glXDisp_RenderMode(__GLXclientState *cl, GLbyte *pc)
108{
109    ClientPtr client;
110    xGLXRenderModeReply reply;
111    __GLXcontext *cx;
112    GLint nitems=0, retBytes=0, retval, newModeCheck;
113    GLubyte *retBuffer = NULL;
114    GLenum newMode;
115    int error;
116
117    cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
118    if (!cx) {
119	return error;
120    }
121
122    pc += __GLX_SINGLE_HDR_SIZE;
123    newMode = *(GLenum*) pc;
124    retval = CALL_RenderMode( GET_DISPATCH(), (newMode) );
125
126    /* Check that render mode worked */
127    CALL_GetIntegerv( GET_DISPATCH(), (GL_RENDER_MODE, &newModeCheck) );
128    if (newModeCheck != newMode) {
129	/* Render mode change failed.  Bail */
130	newMode = newModeCheck;
131	goto noChangeAllowed;
132    }
133
134    /*
135    ** Render mode might have still failed if we get here.  But in this
136    ** case we can't really tell, nor does it matter.  If it did fail, it
137    ** will return 0, and thus we won't send any data across the wire.
138    */
139
140    switch (cx->renderMode) {
141      case GL_RENDER:
142	cx->renderMode = newMode;
143	break;
144      case GL_FEEDBACK:
145	if (retval < 0) {
146	    /* Overflow happened. Copy the entire buffer */
147	    nitems = cx->feedbackBufSize;
148	} else {
149	    nitems = retval;
150	}
151	retBytes = nitems * __GLX_SIZE_FLOAT32;
152	retBuffer = (GLubyte*) cx->feedbackBuf;
153	cx->renderMode = newMode;
154	break;
155      case GL_SELECT:
156	if (retval < 0) {
157	    /* Overflow happened.  Copy the entire buffer */
158	    nitems = cx->selectBufSize;
159	} else {
160	    GLuint *bp = cx->selectBuf;
161	    GLint i;
162
163	    /*
164	    ** Figure out how many bytes of data need to be sent.  Parse
165	    ** the selection buffer to determine this fact as the
166	    ** return value is the number of hits, not the number of
167	    ** items in the buffer.
168	    */
169	    nitems = 0;
170	    i = retval;
171	    while (--i >= 0) {
172		GLuint n;
173
174		/* Parse select data for this hit */
175		n = *bp;
176		bp += 3 + n;
177	    }
178	    nitems = bp - cx->selectBuf;
179	}
180	retBytes = nitems * __GLX_SIZE_CARD32;
181	retBuffer = (GLubyte*) cx->selectBuf;
182	cx->renderMode = newMode;
183	break;
184    }
185
186    /*
187    ** First reply is the number of elements returned in the feedback or
188    ** selection array, as per the API for glRenderMode itself.
189    */
190  noChangeAllowed:;
191    client = cl->client;
192    reply.length = nitems;
193    reply.type = X_Reply;
194    reply.sequenceNumber = client->sequence;
195    reply.retval = retval;
196    reply.size = nitems;
197    reply.newMode = newMode;
198    WriteToClient(client, sz_xGLXRenderModeReply, (char *)&reply);
199    if (retBytes) {
200	WriteToClient(client, retBytes, (char *)retBuffer);
201    }
202    return Success;
203}
204
205int __glXDisp_Flush(__GLXclientState *cl, GLbyte *pc)
206{
207	__GLXcontext *cx;
208	int error;
209
210	cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
211	if (!cx) {
212		return error;
213	}
214
215	CALL_Flush( GET_DISPATCH(), () );
216	__GLX_NOTE_FLUSHED_CMDS(cx);
217	return Success;
218}
219
220int __glXDisp_Finish(__GLXclientState *cl, GLbyte *pc)
221{
222    __GLXcontext *cx;
223    ClientPtr client;
224    int error;
225
226    cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
227    if (!cx) {
228	return error;
229    }
230
231    /* Do a local glFinish */
232    CALL_Finish( GET_DISPATCH(), () );
233    __GLX_NOTE_FLUSHED_CMDS(cx);
234
235    /* Send empty reply packet to indicate finish is finished */
236    client = cl->client;
237    __GLX_BEGIN_REPLY(0);
238    __GLX_SEND_HEADER();
239    return Success;
240}
241
242#define SEPARATOR " "
243
244char *__glXcombine_strings(const char *cext_string, const char *sext_string)
245{
246   size_t clen, slen;
247   char *combo_string, *token, *s1;
248   const char *s2, *end;
249
250   /* safeguard to prevent potentially fatal errors in the string functions */
251   if (!cext_string)
252      cext_string = "";
253   if (!sext_string)
254      sext_string = "";
255
256   /*
257   ** String can't be longer than min(cstring, sstring)
258   ** pull tokens out of shortest string
259   ** include space in combo_string for final separator and null terminator
260   */
261   clen = strlen(cext_string);
262   slen = strlen(sext_string);
263   if (clen > slen) {
264	combo_string = (char *) malloc(slen + 2);
265	s1 = (char *) malloc(slen + 2);
266	if (s1) strcpy(s1, sext_string);
267	s2 = cext_string;
268   } else {
269	combo_string = (char *) malloc(clen + 2);
270	s1 = (char *) malloc(clen + 2);
271	if (s1) strcpy(s1, cext_string);
272	s2 = sext_string;
273   }
274   if (!combo_string || !s1) {
275	free(combo_string);
276	free(s1);
277	return NULL;
278   }
279   combo_string[0] = '\0';
280
281   /* Get first extension token */
282   token = strtok( s1, SEPARATOR);
283   while ( token != NULL ) {
284
285	/*
286	** if token in second string then save it
287	** beware of extension names which are prefixes of other extension names
288	*/
289	const char *p = s2;
290	end = p + strlen(p);
291	while (p < end) {
292	    size_t n = strcspn(p, SEPARATOR);
293	    if ((strlen(token) == n) && (strncmp(token, p, n) == 0)) {
294		combo_string = strcat(combo_string, token);
295		combo_string = strcat(combo_string, SEPARATOR);
296	    }
297	    p += (n + 1);
298	}
299
300	/* Get next extension token */
301	token = strtok( NULL, SEPARATOR);
302   }
303   free(s1);
304   return combo_string;
305}
306
307int DoGetString(__GLXclientState *cl, GLbyte *pc, GLboolean need_swap)
308{
309    ClientPtr client;
310    __GLXcontext *cx;
311    GLenum name;
312    const char *string;
313    __GLX_DECLARE_SWAP_VARIABLES;
314    int error;
315    char *buf = NULL, *buf1 = NULL;
316    GLint length = 0;
317
318    /* If the client has the opposite byte order, swap the contextTag and
319     * the name.
320     */
321    if ( need_swap ) {
322	__GLX_SWAP_INT(pc + 4);
323	__GLX_SWAP_INT(pc + __GLX_SINGLE_HDR_SIZE);
324    }
325
326    cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
327    if (!cx) {
328	return error;
329    }
330
331    pc += __GLX_SINGLE_HDR_SIZE;
332    name = *(GLenum *)(pc + 0);
333    string = (const char *) CALL_GetString( GET_DISPATCH(), (name) );
334    client = cl->client;
335
336    if (string == NULL)
337      string = "";
338
339    /*
340    ** Restrict extensions to those that are supported by both the
341    ** implementation and the connection.  That is, return the
342    ** intersection of client, server, and core extension strings.
343    */
344    if (name == GL_EXTENSIONS) {
345	buf1 = __glXcombine_strings(string,
346				      cl->GLClientextensions);
347	buf = __glXcombine_strings(buf1,
348				      cx->pGlxScreen->GLextensions);
349	if (buf1 != NULL) {
350	    free(buf1);
351	}
352	string = buf;
353    }
354    else if ( name == GL_VERSION ) {
355	if ( atof( string ) > atof( GLServerVersion ) ) {
356	    buf = malloc( strlen( string ) + strlen( GLServerVersion ) + 4 );
357	    if ( buf == NULL ) {
358		string = GLServerVersion;
359	    }
360	    else {
361		sprintf( buf, "%s (%s)", GLServerVersion, string );
362		string = buf;
363	    }
364	}
365    }
366    if (string) {
367	length = strlen((const char *) string) + 1;
368    }
369
370    __GLX_BEGIN_REPLY(length);
371    __GLX_PUT_SIZE(length);
372
373    if ( need_swap ) {
374	__GLX_SWAP_REPLY_SIZE();
375	__GLX_SWAP_REPLY_HEADER();
376    }
377
378    __GLX_SEND_HEADER();
379    WriteToClient(client, length, (char *) string);
380    if (buf != NULL)
381	free(buf);
382
383    return Success;
384}
385
386int __glXDisp_GetString(__GLXclientState *cl, GLbyte *pc)
387{
388    return DoGetString(cl, pc, GL_FALSE);
389}
390