single2.c revision 4642e01f
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#define NEED_REPLIES
32#ifdef HAVE_DIX_CONFIG_H
33#include <dix-config.h>
34#endif
35
36#include <string.h>
37#include <stdio.h>
38#include <stdlib.h>
39
40#include "glxserver.h"
41#include "glxutil.h"
42#include "glxext.h"
43#include "indirect_dispatch.h"
44#include "unpack.h"
45#include "glapitable.h"
46#include "glapi.h"
47#include "glthread.h"
48#include "dispatch.h"
49
50int __glXDisp_FeedbackBuffer(__GLXclientState *cl, GLbyte *pc)
51{
52    GLsizei size;
53    GLenum type;
54    __GLXcontext *cx;
55    int error;
56
57    cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
58    if (!cx) {
59	return error;
60    }
61
62    pc += __GLX_SINGLE_HDR_SIZE;
63    size = *(GLsizei *)(pc+0);
64    type = *(GLenum *)(pc+4);
65    if (cx->feedbackBufSize < size) {
66	cx->feedbackBuf = (GLfloat *) xrealloc(cx->feedbackBuf,
67						   (size_t)size
68						   * __GLX_SIZE_FLOAT32);
69	if (!cx->feedbackBuf) {
70	    cl->client->errorValue = size;
71	    return BadAlloc;
72	}
73	cx->feedbackBufSize = size;
74    }
75    CALL_FeedbackBuffer( GET_DISPATCH(), (size, type, cx->feedbackBuf) );
76    __GLX_NOTE_UNFLUSHED_CMDS(cx);
77    return Success;
78}
79
80int __glXDisp_SelectBuffer(__GLXclientState *cl, GLbyte *pc)
81{
82    __GLXcontext *cx;
83    GLsizei size;
84    int error;
85
86    cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
87    if (!cx) {
88	return error;
89    }
90
91    pc += __GLX_SINGLE_HDR_SIZE;
92    size = *(GLsizei *)(pc+0);
93    if (cx->selectBufSize < size) {
94	cx->selectBuf = (GLuint *) xrealloc(cx->selectBuf,
95						(size_t) size
96						* __GLX_SIZE_CARD32);
97	if (!cx->selectBuf) {
98	    cl->client->errorValue = size;
99	    return BadAlloc;
100	}
101	cx->selectBufSize = size;
102    }
103    CALL_SelectBuffer( GET_DISPATCH(), (size, cx->selectBuf) );
104    __GLX_NOTE_UNFLUSHED_CMDS(cx);
105    return Success;
106}
107
108int __glXDisp_RenderMode(__GLXclientState *cl, GLbyte *pc)
109{
110    ClientPtr client;
111    xGLXRenderModeReply reply;
112    __GLXcontext *cx;
113    GLint nitems=0, retBytes=0, retval, newModeCheck;
114    GLubyte *retBuffer = NULL;
115    GLenum newMode;
116    int error;
117
118    cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
119    if (!cx) {
120	return error;
121    }
122
123    pc += __GLX_SINGLE_HDR_SIZE;
124    newMode = *(GLenum*) pc;
125    retval = CALL_RenderMode( GET_DISPATCH(), (newMode) );
126
127    /* Check that render mode worked */
128    CALL_GetIntegerv( GET_DISPATCH(), (GL_RENDER_MODE, &newModeCheck) );
129    if (newModeCheck != newMode) {
130	/* Render mode change failed.  Bail */
131	newMode = newModeCheck;
132	goto noChangeAllowed;
133    }
134
135    /*
136    ** Render mode might have still failed if we get here.  But in this
137    ** case we can't really tell, nor does it matter.  If it did fail, it
138    ** will return 0, and thus we won't send any data across the wire.
139    */
140
141    switch (cx->renderMode) {
142      case GL_RENDER:
143	cx->renderMode = newMode;
144	break;
145      case GL_FEEDBACK:
146	if (retval < 0) {
147	    /* Overflow happened. Copy the entire buffer */
148	    nitems = cx->feedbackBufSize;
149	} else {
150	    nitems = retval;
151	}
152	retBytes = nitems * __GLX_SIZE_FLOAT32;
153	retBuffer = (GLubyte*) cx->feedbackBuf;
154	cx->renderMode = newMode;
155	break;
156      case GL_SELECT:
157	if (retval < 0) {
158	    /* Overflow happened.  Copy the entire buffer */
159	    nitems = cx->selectBufSize;
160	} else {
161	    GLuint *bp = cx->selectBuf;
162	    GLint i;
163
164	    /*
165	    ** Figure out how many bytes of data need to be sent.  Parse
166	    ** the selection buffer to determine this fact as the
167	    ** return value is the number of hits, not the number of
168	    ** items in the buffer.
169	    */
170	    nitems = 0;
171	    i = retval;
172	    while (--i >= 0) {
173		GLuint n;
174
175		/* Parse select data for this hit */
176		n = *bp;
177		bp += 3 + n;
178	    }
179	    nitems = bp - cx->selectBuf;
180	}
181	retBytes = nitems * __GLX_SIZE_CARD32;
182	retBuffer = (GLubyte*) cx->selectBuf;
183	cx->renderMode = newMode;
184	break;
185    }
186
187    /*
188    ** First reply is the number of elements returned in the feedback or
189    ** selection array, as per the API for glRenderMode itself.
190    */
191  noChangeAllowed:;
192    client = cl->client;
193    reply.length = nitems;
194    reply.type = X_Reply;
195    reply.sequenceNumber = client->sequence;
196    reply.retval = retval;
197    reply.size = nitems;
198    reply.newMode = newMode;
199    WriteToClient(client, sz_xGLXRenderModeReply, (char *)&reply);
200    if (retBytes) {
201	WriteToClient(client, retBytes, (char *)retBuffer);
202    }
203    return Success;
204}
205
206int __glXDisp_Flush(__GLXclientState *cl, GLbyte *pc)
207{
208	__GLXcontext *cx;
209	int error;
210
211	cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
212	if (!cx) {
213		return error;
214	}
215
216	CALL_Flush( GET_DISPATCH(), () );
217	__GLX_NOTE_FLUSHED_CMDS(cx);
218	return Success;
219}
220
221int __glXDisp_Finish(__GLXclientState *cl, GLbyte *pc)
222{
223    __GLXcontext *cx;
224    ClientPtr client;
225    int error;
226
227    cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
228    if (!cx) {
229	return error;
230    }
231
232    /* Do a local glFinish */
233    CALL_Finish( GET_DISPATCH(), () );
234    __GLX_NOTE_FLUSHED_CMDS(cx);
235
236    /* Send empty reply packet to indicate finish is finished */
237    client = cl->client;
238    __GLX_BEGIN_REPLY(0);
239    __GLX_SEND_HEADER();
240    return Success;
241}
242
243#define SEPARATOR " "
244
245char *__glXcombine_strings(const char *cext_string, const char *sext_string)
246{
247   size_t clen, slen;
248   char *combo_string, *token, *s1;
249   const char *s2, *end;
250
251   /* safeguard to prevent potentially fatal errors in the string functions */
252   if (!cext_string)
253      cext_string = "";
254   if (!sext_string)
255      sext_string = "";
256
257   /*
258   ** String can't be longer than min(cstring, sstring)
259   ** pull tokens out of shortest string
260   ** include space in combo_string for final separator and null terminator
261   */
262   clen = strlen(cext_string);
263   slen = strlen(sext_string);
264   if (clen > slen) {
265	combo_string = (char *) xalloc(slen + 2);
266	s1 = (char *) xalloc(slen + 2);
267	if (s1) strcpy(s1, sext_string);
268	s2 = cext_string;
269   } else {
270	combo_string = (char *) xalloc(clen + 2);
271	s1 = (char *) xalloc(clen + 2);
272	if (s1) strcpy(s1, cext_string);
273	s2 = sext_string;
274   }
275   if (!combo_string || !s1) {
276	if (combo_string)
277	    xfree(combo_string);
278	if (s1)
279	    xfree(s1);
280	return NULL;
281   }
282   combo_string[0] = '\0';
283
284   /* Get first extension token */
285   token = strtok( s1, SEPARATOR);
286   while ( token != NULL ) {
287
288	/*
289	** if token in second string then save it
290	** beware of extension names which are prefixes of other extension names
291	*/
292	const char *p = s2;
293	end = p + strlen(p);
294	while (p < end) {
295	    size_t n = strcspn(p, SEPARATOR);
296	    if ((strlen(token) == n) && (strncmp(token, p, n) == 0)) {
297		combo_string = strcat(combo_string, token);
298		combo_string = strcat(combo_string, SEPARATOR);
299	    }
300	    p += (n + 1);
301	}
302
303	/* Get next extension token */
304	token = strtok( NULL, SEPARATOR);
305   }
306   xfree(s1);
307   return combo_string;
308}
309
310int DoGetString(__GLXclientState *cl, GLbyte *pc, GLboolean need_swap)
311{
312    ClientPtr client;
313    __GLXcontext *cx;
314    GLenum name;
315    const char *string;
316    __GLX_DECLARE_SWAP_VARIABLES;
317    int error;
318    char *buf = NULL, *buf1 = NULL;
319    GLint length = 0;
320
321    /* If the client has the opposite byte order, swap the contextTag and
322     * the name.
323     */
324    if ( need_swap ) {
325	__GLX_SWAP_INT(pc + 4);
326	__GLX_SWAP_INT(pc + __GLX_SINGLE_HDR_SIZE);
327    }
328
329    cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
330    if (!cx) {
331	return error;
332    }
333
334    pc += __GLX_SINGLE_HDR_SIZE;
335    name = *(GLenum *)(pc + 0);
336    string = (const char *) CALL_GetString( GET_DISPATCH(), (name) );
337    client = cl->client;
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	    xfree(buf1);
351	}
352	string = buf;
353    }
354    else if ( name == GL_VERSION ) {
355	if ( atof( string ) > atof( GLServerVersion ) ) {
356	    buf = xalloc( 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	xfree(buf);
382
383    return Success;
384}
385
386int __glXDisp_GetString(__GLXclientState *cl, GLbyte *pc)
387{
388    return DoGetString(cl, pc, GL_FALSE);
389}
390