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 
45 int
__glXDisp_FeedbackBuffer(__GLXclientState * cl,GLbyte * pc)46 __glXDisp_FeedbackBuffer(__GLXclientState * cl, GLbyte * pc)
47 {
48     ClientPtr client = cl->client;
49     GLsizei size;
50     GLenum type;
51     __GLXcontext *cx;
52     int error;
53 
54     REQUEST_FIXED_SIZE(xGLXSingleReq, 8);
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 = reallocarray(cx->feedbackBuf,
66                                        (size_t) size, __GLX_SIZE_FLOAT32);
67         if (!cx->feedbackBuf) {
68             cl->client->errorValue = size;
69             return BadAlloc;
70         }
71         cx->feedbackBufSize = size;
72     }
73     glFeedbackBuffer(size, type, cx->feedbackBuf);
74     return Success;
75 }
76 
77 int
__glXDisp_SelectBuffer(__GLXclientState * cl,GLbyte * pc)78 __glXDisp_SelectBuffer(__GLXclientState * cl, GLbyte * pc)
79 {
80     ClientPtr client = cl->client;
81     __GLXcontext *cx;
82     GLsizei size;
83     int error;
84 
85     REQUEST_FIXED_SIZE(xGLXSingleReq, 4);
86 
87     cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
88     if (!cx) {
89         return error;
90     }
91 
92     pc += __GLX_SINGLE_HDR_SIZE;
93     size = *(GLsizei *) (pc + 0);
94     if (cx->selectBufSize < size) {
95         cx->selectBuf = reallocarray(cx->selectBuf,
96                                      (size_t) size, __GLX_SIZE_CARD32);
97         if (!cx->selectBuf) {
98             cl->client->errorValue = size;
99             return BadAlloc;
100         }
101         cx->selectBufSize = size;
102     }
103     glSelectBuffer(size, cx->selectBuf);
104     return Success;
105 }
106 
107 int
__glXDisp_RenderMode(__GLXclientState * cl,GLbyte * pc)108 __glXDisp_RenderMode(__GLXclientState * cl, GLbyte * pc)
109 {
110     ClientPtr client = cl->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     REQUEST_FIXED_SIZE(xGLXSingleReq, 4);
119 
120     cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
121     if (!cx) {
122         return error;
123     }
124 
125     pc += __GLX_SINGLE_HDR_SIZE;
126     newMode = *(GLenum *) pc;
127     retval = glRenderMode(newMode);
128 
129     /* Check that render mode worked */
130     glGetIntegerv(GL_RENDER_MODE, &newModeCheck);
131     if (newModeCheck != newMode) {
132         /* Render mode change failed.  Bail */
133         newMode = newModeCheck;
134         goto noChangeAllowed;
135     }
136 
137     /*
138      ** Render mode might have still failed if we get here.  But in this
139      ** case we can't really tell, nor does it matter.  If it did fail, it
140      ** will return 0, and thus we won't send any data across the wire.
141      */
142 
143     switch (cx->renderMode) {
144     case GL_RENDER:
145         cx->renderMode = newMode;
146         break;
147     case GL_FEEDBACK:
148         if (retval < 0) {
149             /* Overflow happened. Copy the entire buffer */
150             nitems = cx->feedbackBufSize;
151         }
152         else {
153             nitems = retval;
154         }
155         retBytes = nitems * __GLX_SIZE_FLOAT32;
156         retBuffer = (GLubyte *) cx->feedbackBuf;
157         cx->renderMode = newMode;
158         break;
159     case GL_SELECT:
160         if (retval < 0) {
161             /* Overflow happened.  Copy the entire buffer */
162             nitems = cx->selectBufSize;
163         }
164         else {
165             GLuint *bp = cx->selectBuf;
166             GLint i;
167 
168             /*
169              ** Figure out how many bytes of data need to be sent.  Parse
170              ** the selection buffer to determine this fact as the
171              ** return value is the number of hits, not the number of
172              ** items in the buffer.
173              */
174             nitems = 0;
175             i = retval;
176             while (--i >= 0) {
177                 GLuint n;
178 
179                 /* Parse select data for this hit */
180                 n = *bp;
181                 bp += 3 + n;
182             }
183             nitems = bp - cx->selectBuf;
184         }
185         retBytes = nitems * __GLX_SIZE_CARD32;
186         retBuffer = (GLubyte *) cx->selectBuf;
187         cx->renderMode = newMode;
188         break;
189     }
190 
191     /*
192      ** First reply is the number of elements returned in the feedback or
193      ** selection array, as per the API for glRenderMode itself.
194      */
195  noChangeAllowed:;
196     reply = (xGLXRenderModeReply) {
197         .type = X_Reply,
198         .sequenceNumber = client->sequence,
199         .length = nitems,
200         .retval = retval,
201         .size = nitems,
202         .newMode = newMode
203     };
204     WriteToClient(client, sz_xGLXRenderModeReply, &reply);
205     if (retBytes) {
206         WriteToClient(client, retBytes, retBuffer);
207     }
208     return Success;
209 }
210 
211 int
__glXDisp_Flush(__GLXclientState * cl,GLbyte * pc)212 __glXDisp_Flush(__GLXclientState * cl, GLbyte * pc)
213 {
214     ClientPtr client = cl->client;
215     __GLXcontext *cx;
216     int error;
217 
218     REQUEST_SIZE_MATCH(xGLXSingleReq);
219 
220     cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
221     if (!cx) {
222         return error;
223     }
224 
225     glFlush();
226     return Success;
227 }
228 
229 int
__glXDisp_Finish(__GLXclientState * cl,GLbyte * pc)230 __glXDisp_Finish(__GLXclientState * cl, GLbyte * pc)
231 {
232     ClientPtr client = cl->client;
233     __GLXcontext *cx;
234     int error;
235     xGLXSingleReply reply = { 0, };
236 
237     REQUEST_SIZE_MATCH(xGLXSingleReq);
238 
239     cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
240     if (!cx) {
241         return error;
242     }
243 
244     /* Do a local glFinish */
245     glFinish();
246 
247     /* Send empty reply packet to indicate finish is finished */
248     client = cl->client;
249     __GLX_BEGIN_REPLY(0);
250     __GLX_SEND_HEADER();
251     return Success;
252 }
253 
254 #define SEPARATOR " "
255 
256 static char *
__glXcombine_strings(const char * cext_string,const char * sext_string)257 __glXcombine_strings(const char *cext_string, const char *sext_string)
258 {
259     size_t clen, slen;
260     char *combo_string, *token, *s1;
261     const char *s2, *end;
262 
263     /* safeguard to prevent potentially fatal errors in the string functions */
264     if (!cext_string)
265         cext_string = "";
266     if (!sext_string)
267         sext_string = "";
268 
269     /*
270      ** String can't be longer than min(cstring, sstring)
271      ** pull tokens out of shortest string
272      ** include space in combo_string for final separator and null terminator
273      */
274     clen = strlen(cext_string);
275     slen = strlen(sext_string);
276     if (clen > slen) {
277         combo_string = (char *) malloc(slen + 2);
278         s1 = (char *) malloc(slen + 2);
279         if (s1)
280             strcpy(s1, sext_string);
281         s2 = cext_string;
282     }
283     else {
284         combo_string = (char *) malloc(clen + 2);
285         s1 = (char *) malloc(clen + 2);
286         if (s1)
287             strcpy(s1, cext_string);
288         s2 = sext_string;
289     }
290     if (!combo_string || !s1) {
291         free(combo_string);
292         free(s1);
293         return NULL;
294     }
295     combo_string[0] = '\0';
296 
297     /* Get first extension token */
298     token = strtok(s1, SEPARATOR);
299     while (token != NULL) {
300 
301         /*
302          ** if token in second string then save it
303          ** beware of extension names which are prefixes of other extension names
304          */
305         const char *p = s2;
306 
307         end = p + strlen(p);
308         while (p < end) {
309             size_t n = strcspn(p, SEPARATOR);
310 
311             if ((strlen(token) == n) && (strncmp(token, p, n) == 0)) {
312                 combo_string = strcat(combo_string, token);
313                 combo_string = strcat(combo_string, SEPARATOR);
314             }
315             p += (n + 1);
316         }
317 
318         /* Get next extension token */
319         token = strtok(NULL, SEPARATOR);
320     }
321     free(s1);
322     return combo_string;
323 }
324 
325 int
DoGetString(__GLXclientState * cl,GLbyte * pc,GLboolean need_swap)326 DoGetString(__GLXclientState * cl, GLbyte * pc, GLboolean need_swap)
327 {
328     ClientPtr client = cl->client;
329     __GLXcontext *cx;
330     GLenum name;
331     const char *string;
332     xGLXSingleReply reply = { 0, };
333 
334     __GLX_DECLARE_SWAP_VARIABLES;
335     int error;
336     char *buf = NULL, *buf1 = NULL;
337     GLint length = 0;
338 
339     REQUEST_FIXED_SIZE(xGLXSingleReq, 4);
340 
341     /* If the client has the opposite byte order, swap the contextTag and
342      * the name.
343      */
344     if (need_swap) {
345         __GLX_SWAP_INT(pc + 4);
346         __GLX_SWAP_INT(pc + __GLX_SINGLE_HDR_SIZE);
347     }
348 
349     cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error);
350     if (!cx) {
351         return error;
352     }
353 
354     pc += __GLX_SINGLE_HDR_SIZE;
355     name = *(GLenum *) (pc + 0);
356     string = (const char *) glGetString(name);
357 
358     if (string == NULL)
359         string = "";
360 
361     /*
362      ** Restrict extensions to those that are supported by both the
363      ** implementation and the connection.  That is, return the
364      ** intersection of client, server, and core extension strings.
365      */
366     if (name == GL_EXTENSIONS) {
367         buf1 = __glXcombine_strings(string, cl->GLClientextensions);
368         buf = __glXcombine_strings(buf1, cx->pGlxScreen->GLextensions);
369         free(buf1);
370         string = buf;
371     }
372     else if (name == GL_VERSION) {
373         if (atof(string) > atof(GLServerVersion)) {
374             if (asprintf(&buf, "%s (%s)", GLServerVersion, string) == -1) {
375                 string = GLServerVersion;
376             }
377             else {
378                 string = buf;
379             }
380         }
381     }
382     if (string) {
383         length = strlen((const char *) string) + 1;
384     }
385 
386     __GLX_BEGIN_REPLY(length);
387     __GLX_PUT_SIZE(length);
388 
389     if (need_swap) {
390         __GLX_SWAP_REPLY_SIZE();
391         __GLX_SWAP_REPLY_HEADER();
392     }
393 
394     __GLX_SEND_HEADER();
395     WriteToClient(client, length, string);
396     free(buf);
397 
398     return Success;
399 }
400 
401 int
__glXDisp_GetString(__GLXclientState * cl,GLbyte * pc)402 __glXDisp_GetString(__GLXclientState * cl, GLbyte * pc)
403 {
404     return DoGetString(cl, pc, GL_FALSE);
405 }
406