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