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