single2.c revision 7e31ba66
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 return Success; 75} 76 77int 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 107int 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 211int 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 229int 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 256static char * 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 325int 326DoGetString(__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 401int 402__glXDisp_GetString(__GLXclientState * cl, GLbyte * pc) 403{ 404 return DoGetString(cl, pc, GL_FALSE); 405} 406