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